AKI- H8/3048foneのモニタプログラム,クロスアセンブラ環境での
アセンブリ言語プログラミング

Copyright(C)12Mar2014
since 1Aug2003
coskx


1.はじめに

この文書は,AKI-H8におけるH8/3048foneのモニタプログラム,PCターミナルソフトで の学習を記述している。
モニタプログラムは,新しいプログラムの動作を検証する場合や,アセンブリ言語の学習者が,1命令ずつ機械語命令を実行してCPUのふるまいを観察するプ ログラムである。モニタプログラムはROM(フラッシュメモリ)上に配置されており,検証対象のプログラムはRAM上に置かれる。

この文書では
(1)PC上のエディタでアセンブリ言語プログラムを作成し,アセンブラに機械語プログラムに変換
(2)マイコンではモニタプログラムを動作させ,ターミナル画面から機械語プログラムをマイクロコンピュータに転送
(3)モニタプログラム上でこのプログラムを動作させる
手順を解説します。

(本校)校内からは授業に使うため準備用ファイルが入手できます。またマニュアルもダウンロードしておくとよい。

このファイルを解凍すると「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)

または

E0 (16bit)

R0H (8bit)

R0L (8bit)

                  レジスタER0の構造と使われ方

ER0の構造はER1,ER2,ER3,ER4,ER5,ER6でも同じである。
例えばER1では次のようになっている

ER1 (32bit)

または

E1 (16bit)

R1 (16bit)

または

E1 (16bit)

R1H (8bit)

R1L (8bit)

                  レジスタER1の構造と使われ方

もう一例を上げれば,ER2では次のようになっている

ER2 (32bit)

または

E2 (16bit)

R2 (16bit)

または

E2 (16bit)

R2H (8bit)

R2L (8bit)

                  レジスタER2の構造と使われ方

bit,byteと16進表示についてまとめておこう


ビット数
バイト数
16進表現桁数
表現範囲
略号
バイト
8bit
1byte
2桁
00-FF
B
ワード
16bit
2byte
4桁
0000-FFFF
W
ロングワード
32bit
4byte
8桁
00000000-FFFFFFFF
L




2.アセンブリ言語プログラムをエディタで作成し,アセンブルを行い,モニタ上で実行

モニタプログラム上で1行ずつ命令を直打ちしてアッセンブルできるとは言っても,そのまま数十行のプログラムを書くことは現実的ではない。
そこで,アセンブリ言語で書かれたソースプログラムを,汎用エディタ(たとえばTeraPad)で作成し,アセンブルし,リンク,コンバー ト(モトローラS 形式にするとフラッシュメモリ書き込み可能となる)して,.MOTファイルを作って,これまでと同様に1ステップずつ実行してみる。
ただし,通常はROM領域に配置されるプログラムを,RAM領域に置く。

(1)アセンブリ言語で書かれたプログラム例

プログラムは次のようなものである。
 
 スタックポインタを初期化する(使わないのでしなくてもよい)
 FF800番地の2byteデータをレジスタR0に載せる
 FF802番地の2byteデータをレジスタR1に載せる
 R0とR1の値を加えてR0にしまう
 R0のデータをFF804番地にしまう
 作業が終了したので無限ループに入る(OSなしのマイコンのプログラムは終わることが出来ない)
 ただしプログラム起動の時点で,
 FF800番地にはx1234,FF802番地にはx2345,FF804番地にはx3456が入っているものとする。

アセンブリプログラムのしきたり

・先頭が「.」で始まる行は,機械語に翻訳される命令ではなく,コンパイラに対して
 指示を与える擬似命令と呼ばれるものである。
・行の1文字目から始まり「:」で終わる行は,ラベルといって機械語に翻訳はされず,
 機械語ではアドレスに解釈される。
 例えば
「EternalLoop:」はBRA EternalLoopのジャンプ命令の行き先であり,
 「data1:」はff800を,「data2:」はff802を「data3:」はff804を意味している。

 モニタ上で命令を直打ちするよりも,アドレス指定はラベルが使えるため,便利に
 なっている。。
・命令および擬似命令を書く時は,行頭は少なくとも1つのスペースかあるいはタブ
 で始まらなければならない。ここでは4つのスペースを使っている

test.src
ソースプログラムのダウンロード
右クリックでダウンロードしてください

    .CPU 300HA
    .SECTION A,DATA,LOCATE=H'0FF030
    .DATA.L H'0FF130  ;リセットベクトル

    .SECTION P,CODE,LOCATE=H'0FF130
    MOV.L  #H'FFF00,ER7  ;スタックポインタ設定
    MOV.W @data1, r0     ;data1にある値をレジスタr0へ
    MOV.W @data2, r1     ;data2にある値をレジスタr1へ
    ADD.W r1,r0          ;レジスタr0+r1→r0
    MOV.W r0,@data3      ;レジスタr0にある値をdata3へ
EternalLoop:
    BRA EternalLoop ;永久ループ

    .SECTION D,DATA,LOCATE=H'0FF800
data1:
    .DATA.W H'1234
data2:
    .DATA.W H'2345
data3:
    .DATA.W H'3456

    .END

対象CPU群名
ベクタテーブル領域 0FF030から


プログラム領域0FF130から






終端処理(無限ループ)

データ領域0FF800から

2バイトデータ 1234

2バイトデータ 2345

2バイトデータ 3456

H8 命令ニーモニクの説明マニュアル 学内高速読み取りバッファより

(2)アセンブルからコンバートまで
「test.src」を「Asm2Mon.cmd」にドラッグ&ドロップします。フラッシュメモリ書き込み形式ファイル「test.MOT」 ができます。
この「Asm2Mon.cmd」を使用するとソースリストファイル「test.LIS」とマップファイル「test.MAP」も出来ます。

test.LIS

アドレスとプログラムソースの対応を見ると,FF130からFF14Aまでにプログラムがあることがわかる。
ラベル(例えば「data1:」)はただのアドレスとして扱われていることも判る。

** H8S,H8/300 ASSEMBLER Ver.2.0A Evaluation software ** 08/01/03 22:16:40                PAGE     1

     Address Instruction               ProgramSource
    1                             1         .CPU 300HA
    2 0FF030                      2         .SECTION A,DATA,LOCATE=H'0FF030
    3 0FF030 000FF130             3         .DATA.L H'0FF130  ;リセットベクトル
    4                             4    
    5 0FF130                      5         .SECTION P,CODE,LOCATE=H'0FF130
    6 0FF130 7A07000FFF00         6         MOV.L  #H'FFF00,ER7  ;スタックポインタ設定
    7 0FF136 6B20000FF800         7         MOV.W @data1, r0     ;data1にある値をレジスタr0へ
    8 0FF13C 6B21000FF802         8         MOV.W @data2, r1     ;data2にある値をレジスタr1へ
    9 0FF142 0910                 9         ADD.W r1,r0          ;レジスタr0+r1→r0
   10 0FF144 6BA0000FF804        10         MOV.W r0,@data3      ;レジスタr0にある値をdata3へ
   11 0FF14A                     11     EternalLoop:
   12 0FF14A 40FE                12         BRA EternalLoop ;永久ループ
   13                            13    
   14 0FF800                     14         .SECTION D,DATA,LOCATE=H'0FF800
   15 0FF800                     15     data1:
   16 0FF800 1234                16         .DATA.W H'1234
   17 0FF802                     17     data2:
   18 0FF802 2345                18         .DATA.W H'2345
   19 0FF804                     19     data3:
   20 0FF804 3456                20         .DATA.W H'3456
   21                            21    
   22                            22         .END
  *****TOTAL ERRORS       0
  *****TOTAL WARNINGS     0

 ** H8S,H8/300 ASSEMBLER Ver.2.0A Evaluation software ** 08/01/03 22:16:40                PAGE     2

*** CROSS REFERENCE LIST

NAME                             SECTION  ATTR VALUE             SEQUENCE

A                                A        SCT  000FF030      2*
D                                D        SCT  000FF800     14*
EternalLoop                      P             000FF14A     11*   12
P                                P        SCT  000FF130      5*
data1                            D             000FF800      7    15*
data2                            D             000FF802      8    17*
data3                            D             000FF804     10    19*

 ** H8S,H8/300 ASSEMBLER Ver.2.0A Evaluation software ** 08/01/03 22:16:40                PAGE     3

*** SECTION DATA LIST

SECTION                          ATTRIBUTE    SIZE             START

A                                ABS-DATA    0000004           0FF030         
P                                ABS-CODE    000001C           0FF130         
D                                ABS-DATA    0000006           0FF800         

test.MAP

                                        H SERIES LINKAGE EDITOR Ver. 5.3B
 
LINK COMMAND LINE
 
LNK test -PRINT=test
 
                                  H SERIES LINKAGE EDITOR Ver. 5.3B                      PAGE :     1
 
                                        ***     LINKAGE EDITOR LINK MAP LIST      ***
 
 
SECTION   NAME                       START   -   END         LENGTH     UNIT NAME   MODULE NAME
 
ATTRIBUTE  :   DATA  NOSHR
 
A                                 H'000FF030 - H'000FF033   H'00000004      test         test
 
* TOTAL ADDRESS *                 H'000FF030 - H'000FF033   H'00000004
 
ATTRIBUTE  :   CODE  NOSHR
 
P                                 H'000FF130 - H'000FF14B   H'0000001C      test         test
 
* TOTAL ADDRESS *                 H'000FF130 - H'000FF14B   H'0000001C
 
ATTRIBUTE  :   DATA  NOSHR
 
D                                 H'000FF800 - H'000FF805   H'00000006      test         test
 
* TOTAL ADDRESS *                 H'000FF800 - H'000FF805   H'00000006

(3)RAM書き込み
ここでH8CPUのRAM領域へのプログラム書き込みを行う。

この作業の前に,モニタプログラム「MONITOR3048fone.MOT」 の転送(ROM領域への書き込み)が行われている必要がある。
(一度モニタプログラムがROM領域にかきこまれたなら,RAM領域への書き込みは何回でもできる)

RAM領域への書き込みでは,モニタプログラムをRUNモードで動かしておく必要がある

teratermを用いた機械語プログラムの転送ハイパーターミナルを用いた機械語プログラムの転送

1)AKI-H8側はモニタプログラムがRUNしている状態にしておく。

2)PCでは
teratermを起動する。

3)teraterm上で「L」コマンドを与える。
  ("L"+"Enter")

この時のモニタ画面

: L

そのままにしておく

4)転送したいxxxx.motのアイコンをteratermモニタ画面に
  ドロップして,出てきたメニューでファイル送信を選ぶ。

  別の方法
    teraterm
の「ファイル」メニューの
    「ファイル送信」コマンドを実行する。
    ファイルセレクタが出てくるので,
    ファイルの種類を「*.*」にして「test.MOT」を選択する。

5)書き込み終了(数秒待つと次のように表示される)

RAM書き込み終了時のモニタ画面
: L
  Top Address=FF030
  End Address=FF805
:

1)AKI-H8側はモニタプログラムがRUNしている状態にしておく。

2)PCではハイパーターミナルを起動する。

3)ハイパーターミナル上で「L」コマンドを与える。
  ("L"+"Enter")

この時のモニタ画面


: L

そのままにしておく

4)ハイパーターミナルの「転送」メニューの
  「テキストファイルの送信」コマンドを実行する。
  ファイルセレクタが出てくるので,
  ファイルの種類を「*.*」にして「test.MOT」を選択する。

5)書き込み終了(数秒待つと次のように表示される)

RAM書き込み終了時のモニタ画面
: L
  Top Address=FF030
  End Address=FF805
:



(4)実行前の確認
フラッシュメモリ書き込みが終了したら,以下のようにff800番地とff130番地のところに
test.srcの変数データとプログラムが正常にダウンロードされたことを確かめよう。

プログラムソースのラベルが数値のアドレスに変換されたこともわかる。
(例えば「
MOV.W @data1, r0」は「 MOV.W @H'FF800:24,R0」になっている)

内容 モニタ画面
ff800番地付近の
メモリ表示
: d ff800 ff80f
  <ADDR>                  <  D  A  T  A  >                     < ASCII CODE >
  FF800   12 34 23 45 34 56 DB 7B  E2 8C E7 5B 04 80 E7 7A   ".4#E4V.{...[...z"
プログラムの確認
(ディスアセンブル)
2.(2)において
プログラムの末尾
がff14aであること
が読み取れていた。

: da ff130 ff14a
  FF130   7A07000FFF00          MOV.L      #H'000FFF00:32,ER7
  FF136   6B20000FF800          MOV.W      @H'FF800:24,R0
  FF13C   6B21000FF802          MOV.W      @H'FF802:24,R1
  FF142   0910                  ADD.W      R1,R0
  FF144   6BA0000FF804          MOV.W      R0,@H'FF804:24
  FF14A   40FE                  BRA        FF14A:8

(5)実行
1ステップずつ実行します。

内容 モニタ画面
レジスタの確認 : r
  PC=0FF11A  CCR=80:I.......  SP=000FFF10
  ER0=00000000  ER1=00000000  ER2=00000000  ER3=00000000
  ER4=00000000  ER5=00000000  ER6=00000000  ER7=000FFF10
プログラムカウン
タ(PC)にスター
トすべき先頭アド
レスをセット*1
: .pc
  PC=0FF11A  ?  0ff130
  CCR=80  ?  .
レジスタの確認 : r
  PC=0FF130  CCR=80:I.......  SP=00FFFF10
  ER0=00000000  ER1=00000000  ER2=00000000  ER3=00000000
  ER4=00000000  ER5=00000000  ER6=00000000  ER7=00FFFF10
1ステップずつ
実行
: s
  PC=0FF136  CCR=80:I.......  SP=000FFF00
  ER0=00000000  ER1=00000000  ER2=00000000  ER3=00000000
  ER4=00000000  ER5=00000000  ER6=00000000  ER7=000FFF00
  FF130   7A07000FFF00          MOV.L      #H'000FFF00:32,ER7
: s
  PC=0FF13C  CCR=80:I.......  SP=000FFF00
  ER0=00001234  ER1=00000000  ER2=00000000  ER3=00000000
  ER4=00000000  ER5=00000000  ER6=00000000  ER7=000FFF00
  FF136   6B20000FF800          MOV.W      @H'FF800:24,R0
: s
  PC=0FF142  CCR=80:I.......  SP=000FFF00
  ER0=00001234  ER1=00002345  ER2=00000000  ER3=00000000
  ER4=00000000  ER5=00000000  ER6=00000000  ER7=000FFF00
  FF13C   6B21000FF802          MOV.W      @H'FF802:24,R1
: s
  PC=0FF144  CCR=80:I.......  SP=000FFF00
  ER0=00003579  ER1=00002345  ER2=00000000  ER3=00000000
  ER4=00000000  ER5=00000000  ER6=00000000  ER7=000FFF00
  FF142   0910                  ADD.W      R1,R0
: s
  PC=0FF14A  CCR=80:I.......  SP=000FFF00
  ER0=00003579  ER1=00002345  ER2=00000000  ER3=00000000
  ER4=00000000  ER5=00000000  ER6=00000000  ER7=000FFF00
  FF144   6BA0000FF804          MOV.W      R0,@H'FF804:24
:

ff800番地
付近のメモリ
表示 *2

: d ff800 ff80f
  <ADDR>                  <  D  A  T  A  >                     < ASCII CODE >
  FF800   12 34 23 45 35 79 DB 7B  E2 8C E7 5B 04 80 E7 7A   ".4#E5y.{...[...z"

*1 直前のレジスタ確認で,プログラムカウンタPCがFF130になっているときはこの作業は不要である。
*2 プログラム実行前のメモリ内容表示と比較するとプログラムが意図したとおりに動作したことが判る。


3.プログラムのブレークポイントまでの実行

2.(1)~(3)によってプログラムがすでに書き込まれているとして,FF14Aにブレークポインタ
ここまで実行されたら,止まってモニタに制御を戻せというしるし)を設定し,プログラム先頭から
ブレーク ポインタまでを一気に動作させる。

(1)実行前の確認
以下のようにff800番地付近にデータが,ff130番地のところにプログラムが存在することを確かめよう。
和が格納されるべきアドレス FF804に実行後に和が格納されることを確かめられるように,mコマンドで
適当な値に変更しておくとよい。

内容 モニタ画面
ff800番地付近の
メモリ表示
: d ff800 ff80f
  <ADDR>                  <  D  A  T  A  >                     < ASCII CODE >
  FF800   12 34 23 45 00 00 DB 7B  E2 8C E7 5B 04 80 E7 7A   ".4#E...{...[...z"
プログラムの確認
(ディスアセンブル)
2.(2)において
プログラムの末尾
がff14aであること
が読み取れていた。

: da ff130 ff14a
  FF130   7A07000FFF00          MOV.L      #H'000FFF00:32,ER7
  FF136   6B20000FF800          MOV.W      @H'FF800:24,R0
  FF13C   6B21000FF802          MOV.W      @H'FF802:24,R1
  FF142   0910                  ADD.W      R1,R0
  FF144   6BA0000FF804          MOV.W      R0,@H'FF804:24
  FF14A   40FE                  BRA        FF14A:8

(2)実行
ブレークポインタを設定して実行します。

内容 モニタ画面
レジスタの確認 : r
  PC=0FF11A  CCR=80:I.......  SP=000FFF10
  ER0=00000000  ER1=00000000  ER2=00000000  ER3=00000000
  ER4=00000000  ER5=00000000  ER6=00000000  ER7=000FFF10
プログラムカウンタ
(PC)の変更
*1
: .pc
  PC=0FF11A  ?  0ff130
  CCR=80  ?  .
レジスタの確認 : r
  PC=0FF130  CCR=80:I.......  SP=00FFFF10
  ER0=00000000  ER1=00000000  ER2=00000000  ER3=00000000
  ER4=00000000  ER5=00000000  ER6=00000000  ER7=00FFFF10
ブレークポインタ
の設定
2.(2)において
プログラムの末尾
がff14aであること
が読み取れていた。

: b ff14a
現在のプログラム
カウンタのアドレスから
ブレークポインタまで
実行
: g
  Break at PC=FF14A
  PC=0FF14A  CCR=80:I.......  SP=000FFF00
  ER0=00003579  ER1=00002345  ER2=00000000  ER3=00000000
  ER4=00000000  ER5=00000000  ER6=00000000  ER7=000FFF00

ff800番地付近の
メモリ表示

: d ff800 ff80f
  <ADDR>                  <  D  A  T  A  >                     < ASCII CODE >
  FF800   12 34 23 45 35 79 DB 7B  E2 8C E7 5B 04 80 E7 7A   ".4#E5y.{...[...z"

*1 すでにプログラムカウンタPCがFF130になっているときはこの作業は不要です。

注意 もしブレークポインタをセットせずにgコマンドで起動すると,そのまま
BRA        FF14A:8
のところで無限ループに突入するため,モニタのコマンドを受け付けなくなってしまう。
このような場合には,H8の電源を落とすしかない



参考 プログラムの工夫とGコマンドの工夫によって手間を省く

(1)プログラムの終端に自分自身へのジャンプ命令を置いて無限ループを作る代わりに,モニタの先頭アド レスへジャンプさせてモニタを再起動させてもメモリの内容は変化しないので,プログラムの終端をモニタの先頭アドレスへジャンプするように変更する。この ようにすると,モニタ内でプログラム終端でモニタに制御を戻すためのブレークポインタの設定は不要になる。

(2)Gコマンドは,起動アドレスも指示できるので,PCへの操作を省くことができる。

EQU擬似命令はC言語の#defineと同じ働きをする。プログラム本体に「RESTART」が出てきたら,それは「H'100」としてアセンブルしなさいの意味である。
ゆえに,JMP @RESTART は JMP @H'100 とおなじであり,「アドレス0x100にジャンプしなさい」の意味になる。

(0x100はモニタの先頭アドレス(=モニタの起動アドレス))

test1.src
ソースプログラムのダウンロード
右クリックでダウンロードしてください

    .CPU 300HA
RESTART   .EQU H'100     ;モニタの先頭アドレス
    .SECTION A,DATA,LOCATE=H'0FF030
    .DATA.L H'0FF130  ;リセットベクトル

    .SECTION P,CODE,LOCATE=H'0FF130
    MOV.L  #H'FFF00,ER7  ;スタックポインタ設定
    MOV.W @data1, r0     ;data1にある値をレジスタr0へ
    MOV.W @data2, r1     ;data2にある値をレジスタr1へ
    ADD.W r1,r0          ;レジスタr0+r1→r0
    MOV.W r0,@data3      ;レジスタr0にある値をdata3へ
    JMP @RESTART         ;モニターに戻る

    .SECTION D,DATA,LOCATE=H'0FF800
data1:
    .DATA.W H'1234
data2:
    .DATA.W H'2345
data3:
    .DATA.W H'3456

    .END



ベクタテーブル領域 0FF030から


プログラム領域0FF130から







データ領域0FF800から

2バイトデータ 1234

2バイトデータ 2345

2バイトデータ 3456


実行の様子
モニタが再起動しているのがわかる。
: l
  Top Address=FF030
  End Address=FF805
: da ff130 ff14a
  <ADDR>  <CODE>                <MNEMONIC> <OPERAND>
  FF130   7A07000FFF00          MOV.L      #H'000FFF00:32,ER7
  FF136   6B20000FF800          MOV.W      @H'FF800:24,R0
  FF13C   6B21000FF802          MOV.W      @H'FF802:24,R1
  FF142   0910                  ADD.W      R1,R0
  FF144   6BA0000FF804          MOV.W      R0,@H'FF804:24
  FF14A   5A000100              JMP        @H'00100:24
: d ff800 ff80f
  <ADDR>                  <  D  A  T  A  >                     < ASCII CODE >
  FF800   12 34 23 45 34 56 FF FF  DF EC FD FF FF FF FF FF   ".4#E4V.........."
: g ff130


 H8/3048 Series Advanced Mode Monitor Ver. 3.0A
 Copyright (C) 2003 Renesas Technology Corp.

: d ff800 ff80f
  <ADDR>                  <  D  A  T  A  >                     < ASCII CODE >
  FF800   12 34 23 45 35 79 FF FF  DF EC FD FF FF FF FF FF   ".4#E5y.........."
:



4. メモリ領域のフィル

メモリの指定された領域(アドレス◯◯からアドレス□□まで)を,ある値で埋め尽くします。
実際には,メモリ上の指定されたアドレスから順番に,埋めるべき値を書き込んでいきます。
そして必要なバイト数だけ作業したら終了します。

例題1

アセンブラを用いて次のプログラムを作成しなさい。
(FF200から機械語プログラムを置きなさい。)
FF800番地 - FF83F番地メモリすべてに0x55を埋めるプログラム。

以下を報告しなさい。
実行前のFF800番地 - FF83F番地のメモリ表示
プログラムの逆アッセンブル結果
ブレークポイントを設定して実行した時の実行の様子
実行後のFF800番地 - FF83F番地のメモリ表示
(実行前のメモリ表示と比較して,意図した動作ができているかどうか確かめる)

プログラムの
概要
メモリのある領域を1バイトのデータで埋めるためには,次のようにすればよい。

◯使用するレジスタ
(1)値を埋めるアドレスを保管するレジスタA(最低24ビット必要)
(2)埋める値を保管する1バイトのレジスタB
(3)埋めた数を数えるレジスタC
  (ここでは40(Hex)個数えれば良いので1バイトのレジスタで足りる)
  (ダウンカウントで数えて,繰り返し作業の終了を判断する)

◯作業手順
(1)レジスタAに作業対象先頭アドレスを設定
(2)レジスタBに埋めるべき値を設定
(3)レジスタCに埋める個数を設定
(4)レジスタAの指しているアドレスにレジスタBの値を保存
(5)レジスタAの値を1増やす
(6)レジスタCの値を1減らす
(7)レジスタCの値が0になっていなかったら(4)に戻る

レジスタA,B,Cはプログラムでは実在するレジスタを割り当てる。
アセンブリ
プログラム
testfill.src

ソースプログ
ラムの
ダウンロード
右クリック
でダウンロ
ードしてく
ださい

青字:レジスタ
初期設定


紫字:作業ル
ープ


    .CPU 300HA
    .SECTION A,DATA,LOCATE=H'0FF030
    .DATA.L H'0FF200  ;リセットベクトル

    .SECTION P,CODE,LOCATE=H'0FF200
    MOV.L  #H'FFF00,ER7  ;スタックポインタ設定
    MOV.L  #area,ER1     ;作業対象先頭アドレスをレジスタer1へ
    MOV.B  #H'55, r0l    ;埋める値0x55をレジスタr0lへ
    MOV.B  #H'40, r0h    ;埋める個数0x40をレジスタr0h

L001:
    MOV.B  r0l,@ER1      ;0x55をER1の指しているところへ
    INC.L  #1,ER1        ;ER1を1増やす(32bit操作)
    DEC.B  r0h           ;R0Hを1減らす(8bit操作)
    BNE    L001:8        ; r0h!=0の場合はL001へジャンプ

EternalLoop:
    BRA EternalLoop ;永久ループ

    .SECTION D,DATA,LOCATE=H'0FF800   ;データ領域0FF800から
area:
    .res.b H'40          ;40バイトの領域を確保 先頭アドレスはFF800になる
    .END

プログラムの
補足説明
行の1文字目から書かれる名前はラベルと呼ばれ,ジャンプ命令の行き先となる。
(ラベルは,機械語に変換されるとアドレスになる。)
「BNE L001:8」 直前の操作の結果が0でなかったら,L001にジャンプする
        (Branch Not Equal to 0)
ある条件が成り立ったらジャンプするという命令は条件ジャンプと呼ばれ,
C言語でいうところのif文の構造を作ったり,ループ構造を作ったりするのに
必須の命令である。
条件ジャンプ(条件ブランチ)は多くの種類があるため,命令マニュアルでは
「Bcc」として一括して説明されている。
ファイルの
準備
アセンブルして,testfill.srcからtestfill.MOTを作成する。
このときtestfill.LISもできるので,.LISファイルをエディタで開いて
プログラムの最終アドレスを読み取っておく必要がある。
そうしないと逆アセンブルする時,プログラムの最終アドレスがわからなくなる。
ここでは0FF218が読み取れるはずである。
RAM領域へ
プログラムを
転送
逆アセンブル
してプログラ
ムを確認








作業範囲の
メモリを確認





fコマンドで
ff800-ff84fを
aaで埋めておく


作業範囲の
メモリを確認
AAが埋められた





ブレークポイ
ントの設定



実行




メモリの状態を
実行前と実行後
を比べて,意図
した作業ができ
ているかどうか
検証している
: l
  Top Address=FF030
  End Address=FF219
: da ff200 ff219
  <ADDR>  <CODE>                <MNEMONIC> <OPERAND>
  FF200   7A07000FFF00          MOV.L      #H'000FFF00:32,ER7
  FF206   7A01000FF800          MOV.L      #H'000FF800:32,ER1
  FF20C   F855                  MOV.B      #H'55:8,R0L
  FF20E   F040                  MOV.B      #H'40:8,R0H
  FF210   6898                  MOV.B      R0L,@ER1
  FF212   0B71                  INC.L      #1,ER1
  FF214   1A00                  DEC.B      R0H
  FF216   46F8                  BNE        FF210:8
  FF218   40FE                  BRA        FF218:8
: d ff800 ff85f
  <ADDR>                  <  D  A  T  A  >                     < ASCII CODE >
  FF800   FF FF 7F DF FF FF FF FF  DF EC FD FF FF FF FF FF   "................"
  FF810   FF FF EF F3 FF AF FF F7  FF EB DE F7 FF FF FF FF   "................"
  FF820   DF FF FF FF FF BF FB FF  AF DF DF FF BF FB FF FF   "................"
  FF830   FF F9 7E EF FF DC BF DB  FA FF FF FF 9D FF FD FF   "..~............."
  FF840   FF FF FF FF FF DF DF FF  FF FF 7F FF FF F7 BE FF   "................"
  FF850   6F FF FF E7 FF FF DF FF  97 F7 FA FF BE F3 FF 27   "o..............'"
: f ff800 ff84f aa
: d ff800 ff85f
  <ADDR>                  <  D  A  T  A  >                     < ASCII CODE >
  FF800   AA AA AA AA AA AA AA AA  AA AA AA AA AA AA AA AA   "................"
  FF810   AA AA AA AA AA AA AA AA  AA AA AA AA AA AA AA AA   "................"
  FF820   AA AA AA AA AA AA AA AA  AA AA AA AA AA AA AA AA   "................"
  FF830   AA AA AA AA AA AA AA AA  AA AA AA AA AA AA AA AA   "................"
  FF840   AA AA AA AA AA AA AA AA  AA AA AA AA AA AA AA AA   "................"
  FF850   6F FF FF E7 FF FF DF FF  97 F7 FA FF BE F3 FF 27   "o..............'"
: .pc
  PC=0FF200  ?  ff200
  CCR=80  ?  .
: b ff218
: r
  PC=0FF200  CCR=80:I.......  SP=000FFF00
  ER0=00000000  ER1=00000000  ER2=00000000  ER3=00000000
  ER4=00000000  ER5=00000000  ER6=00000000  ER7=000FFF00
: g
  Break at PC=FF218
  PC=0FF218  CCR=84:I....Z..  SP=000FFF00
  ER0=00000055  ER1=000FF840  ER2=00000000  ER3=00000000
  ER4=00000000  ER5=00000000  ER6=00000000  ER7=000FFF00
: d ff800 ff84f
  <ADDR>                  <  D  A  T  A  >                     < ASCII CODE >
  FF800   55 55 55 55 55 55 55 55  55 55 55 55 55 55 55 55   "UUUUUUUUUUUUUUUU"
  FF810   55 55 55 55 55 55 55 55  55 55 55 55 55 55 55 55   "UUUUUUUUUUUUUUUU"
  FF820   55 55 55 55 55 55 55 55  55 55 55 55 55 55 55 55   "UUUUUUUUUUUUUUUU"
  FF830   55 55 55 55 55 55 55 55  55 55 55 55 55 55 55 55   "UUUUUUUUUUUUUUUU"
  FF840   AA AA AA AA AA AA AA AA  AA AA AA AA AA AA AA AA   "................"
:

モニタコマンド f(fill) について
上記の実行中で 「f ff800 ff84f aa」という命令を行なっている,
これは,メモリのff800からff84fまでをaaで埋めるという命令である。

作成したフィルプログラムが正しく動作したかどうかどうかを検証するためには,
予め検証が可能なように,少し余計な範囲まで,異なる値を埋めておく必要がある。
(プログラムのミスで意図した領域を超えて値を埋めてしまうことがあるため)

H8 命令ニーモニクの説明マニュアル 学内高速読み取りバッファより

課題4.1

テキストエディタとアセンブラを用いて次のプログラムを作成しなさい。
(FF200から機械語プログラムを置きなさい。)
FF800番地 - FF9FF番地メモリすべてに0xccを埋めるプログラム。

プログラム本体および以下を報告しなさい。
(このプログラムの実行の正しさを検証するために工夫すること)
(---プログラムの実行前にfコマンドでFF800番地 - FFA0F番地に55を埋めておくとよい)

実行前のFF800番地 - FFA0F番地の様子
プログラムの逆アッセンブル結果
ブレークポイントを設定して実行した時の実行の様子
実行後のFF800番地 - FFA0F番地の様子
実行前の様子と比較して,意図した動作ができていることを確認する。
(mon2ex01.txt)

ヒント 8bitのレジスタの扱うことのできる値の範囲は0 - 255
    16bitのレジスタの扱うことのできる値の範囲は0 - 65535
ヒント dec命令では8bitレジスタに対する場合と16bit以上のレジスタに対する場合で
    書式が異なる。8bitレジスタ向けdec命令では増分は1と決まっているが,
    16bitレジスタ向けでは増分は1と2の2種類あり,どちらであるかを指定する。

 

5. メモリ領域のブロック転送

メモリの特定の領域を,別の領域にまるごとコピーする。
メモリ保存値を直接他のアドレスに保存することは出来ないので,レジスタ経由でコピーする。
実際にはコピー元のアドレスから1バイト読みだして,コピー先アドレスに
1バイト書き込む。
この作業を,
コピー元のアドレスとコピー先アドレスを1増やしながら,必要な回数行なったら終了する。

例題1

アセンブラを用いて次のプログラムを作成しなさい。
FF200から機械語プログラムを置きなさい。
0番地から3F番地のメモリ内容をFF800番地 - FF83F番地にコピーしなさい。

以下を報告しなさい。
0番地 - 3F番地のメモリ表示
実行前のFF800番地 - FF83F番地のメモリ表示
プログラムの逆アッセンブル結果
ブレークポイントを設定して実行した時の実行の様子
実行後のFF800番地 - FF83F番地のメモリ表示
(実行前のメモリ表示と比較して,意図した動作ができているかどうか確かめる)

プログラムの
概要

ブロック転送の考え方
1バイトずつ,メモリ内容をコピーする

◯使用するレジスタ
(1)コピー元のアドレスを保管するレジスタA(最低24ビット必要)
(2)コピー先のアドレスを保管するレジスタB(最低24ビット必要)
(3)コピーバイト数を数えるレジスタC
  (ここでは40(Hex)個数えれば良いので1バイトのレジスタで足りる)
  (ダウンカウントで数えて,繰り返し作業の終了を判断する)
(4)コピーのための値の一時的な保管場所として使う1バイトレジスタD

◯作業手順
(1)レジスタAにコピー元先頭アドレスを設定
(2)レジスタBにコピー先先頭アドレスを設定
(3)レジスタCにコピーする個数を設定
(4)レジスタAの指しているアドレスの1バイト値をレジスタDにコピー
(5)レジスタDの値をレジスタBの指しているアドレスに1バイトコピー
(6)レジスタAの値を1増やす
(7)レジスタBの値を1増やす
(8)レジスタCの値を1減らす
(9)レジスタCの値が0になっていなかったら(4)に戻る

レジスタA,B,C,Dはプログラムでは実在するレジスタを割り当てる。

アセンブリ
プログラム
testmove.src

ソースプログ
ラムの
ダウンロード
右クリック
でダウンロ
ードしてく
ださい

青字:レジスタ
初期設定


紫字:作業ル
ープ


     .CPU 300HA
    .SECTION A,DATA,LOCATE=H'0FF030
    .DATA.L H'0FF200  ;リセットベクトル

    .SECTION P,CODE,LOCATE=H'0FF200
    MOV.L  #H'FFF00,ER7  ;スタックポインタ設定
    MOV.L  #0,ER1        ;コピー元先頭アドレスをレジスタer1へ
    MOV.L  #area,ER2     ;コピー先先頭アドレスをレジスタer2へ
    MOV.B  #H'40, r0h    ;コピー個数0x40をレジスタr0h

L001:
    MOV.B  @ER1,r0l      ;ER1(コピー元アドレス)の指しているバイト値をr0lへ
    MOV.B  r0l,@ER2      ;r0lの値をER2(コピー先アドレス)の指しているところへ
    INC.L  #1,ER1        ;ER1を1増やす(32bit操作)
    INC.L  #1,ER2        ;ER2を1増やす(32bit操作)
    DEC.B  r0h           ;R0Hを1減らす(8bit操作)
    BNE    L001:8        ;r0h!=0の場合はL001へジャンプ

EternalLoop:
    BRA EternalLoop ;永久ループ

    .SECTION D,DATA,LOCATE=H'0FF800   ;データ領域0FF800から
area:
    .res.b H'40          ;40バイトの領域を確保 先頭アドレスはFF800になる
    .END

ファイルの
準備
アセンブルして,testmove.srcからtestmove.MOTを作成する。
このときtestmove.LISもできるので,.LISファイルをエディタで開いて
プログラムの最終アドレスを読み取っておく必要がある。
そうしないと逆アセンブルする時,プログラムの最終アドレスがわからなくなる。
ここでは0FF220が読み取れるはずである。
RAM領域へ
プログラムを
転送
逆アセンブル
して,プログ
ラムを確認










作業範囲の
メモリを確認





fコマンドで
ff800-ff84fを
aaで埋めておく


作業範囲の
メモリを確認
AAが埋められた


コピー元の
確認









ブレークポイ
ントの設定



実行





メモリの状態を
実行前と実行後
を比べて,意図
した作業ができ
ているかどうか
検証している
: L
  Top Address=FF030
  End Address=FF221
: da ff200 ff221
  <ADDR>  <CODE>                <MNEMONIC> <OPERAND>
  FF200   7A07000FFF00          MOV.L      #H'000FFF00:32,ER7
  FF206   7A0100000000          MOV.L      #H'00000000:32,ER1
  FF20C   7A02000FF800          MOV.L      #H'000FF800:32,ER2
  FF212   F040                  MOV.B      #H'40:8,R0H
  FF214   6818                  MOV.B      @ER1,R0L
  FF216   68A8                  MOV.B      R0L,@ER2
  FF218   0B71                  INC.L      #1,ER1
  FF21A   0B72                  INC.L      #1,ER2
  FF21C   1A00                  DEC.B      R0H
  FF21E   46F4                  BNE        FF214:8
  FF220   40FE                  BRA        FF220:8
: d ff800 ff85f
  <ADDR>                  <  D  A  T  A  >                     < ASCII CODE >
  FF800   FF FF 7F DF FF FF FF DF  DF EC F5 FF FF FF FF FF   "................"
  FF810   FF FF EF F3 FF BF FE F7  FF EB DE F7 FF FF FF FF   "................"
  FF820   DF FF FF FF FF BF FB FF  AF DF DF FF BF FA FF FF   "................"
  FF830   FF FD 7E EF FB DE BF DB  FA FF FF FF 9D FF FD FF   "..~............."
  FF840   FF FF FF FF FF DF DF FF  FF FF 7F FF FF F7 BE FF   "................"
  FF850   6F FE FF E7 FF FF DF FF  97 FF FA FF BE F3 FF 27   "o..............'"
: f ff800 ff84f aa
: d ff800 ff85f
  <ADDR>                  <  D  A  T  A  >                     < ASCII CODE >
  FF800   AA AA AA AA AA AA AA AA  AA AA AA AA AA AA AA AA   "................"
  FF810   AA AA AA AA AA AA AA AA  AA AA AA AA AA AA AA AA   "................"
  FF820   AA AA AA AA AA AA AA AA  AA AA AA AA AA AA AA AA   "................"
  FF830   AA AA AA AA AA AA AA AA  AA AA AA AA AA AA AA AA   "................"
  FF840   AA AA AA AA AA AA AA AA  AA AA AA AA AA AA AA AA   "................"
  FF850   6F FE FF E7 FF FF DF FF  97 FF FA FF BE F3 FF 27   "o..............'"
: d 0 4f
  <ADDR>                  <  D  A  T  A  >                     < ASCII CODE >
  00000   00 00 01 00 00 00 28 16  00 00 28 1A 00 00 28 1E   "......(...(...(."
  00010   00 00 28 22 00 00 28 26  00 00 28 2A 00 00 28 2E   "..("..(&..(*..(."
  00020   00 00 28 32 00 00 28 36  00 00 28 3A 00 00 28 3E   "..(2..(6..(:..(>"
  00030   00 00 28 42 00 00 28 46  00 00 28 4A 00 00 28 4E   "..(B..(F..(J..(N"
  00040   00 00 28 52 00 00 28 56  00 00 28 5A 00 00 28 5E   "..(R..(V..(Z..(^"
: .pc
  PC=0FF200  ?  ff200
  CCR=80  ?  .
: b ff220
: r
  PC=0FF200  CCR=80:I.......  SP=000FFF00
  ER0=00000000  ER1=00000000  ER2=00000000  ER3=00000000
  ER4=00000000  ER5=00000000  ER6=00000000  ER7=000FFF00
: g
  Break at PC=FF220
  PC=0FF220  CCR=84:I....Z..  SP=000FFF00
  ER0=0000004E  ER1=00000040  ER2=000FF840  ER3=00000000
  ER4=00000000  ER5=00000000  ER6=00000000  ER7=000FFF00
: d ff800 ff84f
  <ADDR>                  <  D  A  T  A  >                     < ASCII CODE >
  FF800   00 00 01 00 00 00 28 16  00 00 28 1A 00 00 28 1E   "......(...(...(."
  FF810   00 00 28 22 00 00 28 26  00 00 28 2A 00 00 28 2E   "..("..(&..(*..(."
  FF820   00 00 28 32 00 00 28 36  00 00 28 3A 00 00 28 3E   "..(2..(6..(:..(>"
  FF830   00 00 28 42 00 00 28 46  00 00 28 4A 00 00 28 4E   "..(B..(F..(J..(N"
  FF840   AA AA AA AA AA AA AA AA  AA AA AA AA AA AA AA AA   "................"
:

メモリ内容の検証では1行多く表示しているが,これは,コピー作業領域を間違えて,
余計なところまでメモリを書き換えていないかどうか確かめるためである。

課題5.1

テキストエディタとアセンブラを用いて次のプログラムを作成しなさい。
FF200から機械語プログラムを置きなさい。
プログラムの行うべき作業(1つのプログラムでこれを行う)
(1)FF800番地 - FF87F番地メモリすべてに0x80を埋める。
(2)次にFF800番地 - FF87F番地のメモリの内容をFF900番地
 - FF97F番地にコピーする。(この作業がブロック転送)
(3)さらに続けて,FF200番地 - FF25F番地のメモリの内容をFF900番地
 - FF95F番地にコピーする。(この作業もブロック転送)

すなわちこのプログラムには3つのループを作ることになる。
1回めのブロック転送部では,FF800番地 - FF87F番地に保存されている
値はわかっていない想定で作ること。

プログラム本体および以下を報告しなさい。
(このプログラムの実行の効果がわかるように工夫すること)
(---プログラム実行前にfコマンドでFF800番地 - FF88F番地に66を埋め,
FF900番地 - FF98F番地に77を埋めておくとよい)

プログラムの逆アッセンブル結果
プログラム実行前のFF800番地 - FF98F番地の様子
プログラム実行前のFF200番地 - FF25F番地の様子
ブレークポイントを設定して実行した時の実行の様子
実行後のFF800番地 - FF98F番地の様子
実行前の様子と比較して,意図した動作ができていることを確認する。
(mon2ex02.txt)

補足 次のように記述するとコピー元とコピー先が指定の場所に確保できる

    .SECTION D,DATA,LOCATE=H'0FF800
    .org H'0FF800   ;origin 起点の意味
array:
    .res.b H'80
   
    .org H'0FF900
array2:
    .res.b H'80


ヒント プログラムの構成は次のようになる。(2つのループ)
メモリフィルのためのレジスタ初期設定
メモリフィルのループ
メモリブロック移動のためのレジスタ初期設定
メモリブロック移動のループ
2つ目のメモリブロック移動のためのレジスタ初期設定
2つ目のメモリブロック移動のループ
終端処理(無限ループ)


6. IOポート

(1)LEDの点灯
ここでアセンブリプログラムによるIOポートへのアクセスを試みる。
IOポートのうち,LEDのつながれているP5と,8bitスイッチがつながれているP2を対象とする。

LED0,LED1はP5(正確にはP5DR)のbit0,bit1に保護抵抗を介して接続されている。

P5と呼んでいるポートの実体はメモリ空間に割り当てられているIOレジスタである。
LEDの点滅をするためには,次の2つのことが必要である。点滅対象はLED0の1つだけとする。
(1)P5DDR(Data Direction Register)は,P5DRの各ビットを入力(外部から0Vor5VをCPUとし
   て0or1として受け取る)か出力(CPUの0or1を外部に対して0Vor5Vとして出力する)かを決
   定するレジスタである。
   各ビットを1にすると出力設定となり,0にすると入力設定となる。
   ここではbit0を1にするとLED0への出力となる。
(2)P5DRは,CPUが書き込んだ値をそのままCPUのピンにそのまま出力する8ビットのレジスタである。
   このレジスタのbit0に1を出力すると5Vが出力され点灯,0を出力すると0Vが出力され消灯する。

H8/3048のハードウェアマニュアルによれば,P5DDRはメモリ空間上の1byteのように見える。
P5DDRのアドレスは,0xFFFC8である。
同様にP5DRもメモリ空間上の1byteのように見える。
P5DRのアドレスは。0xFFFCAである。
これらのアドレスは,CPU設計時に決められているため,変更することはできない。

モニタプログラムのmコマンド(メモリ直接書き込み)で,LEDの点滅をさせてみよう。
fffc8に3を設定してP5の下位2ビットを出力に設定
その後,fffcaに01,02,03,00の順に値をするとLED0のみ点灯,LED1のみ点灯,両方点灯,両方消灯の順に推移する。
次のようにモニタプログラムでLED点灯を確認しなさい。

: m fffc8
  FFFC8   FF  ?  03
  FFFC9   FF  ?  .
: m fffca
  FFFCA   F0  ?  01
  FFFCB   FB  ?  .
: m fffca
  FFFCA   F1  ?  02
  FFFCB   FB  ?  .
: m fffca
  FFFCA   F2  ?  03
  FFFCB   FB  ?  .
: m fffca
  FFFCA   F3  ?  00
  FFFCB   FB  ?  .
:


P5の下位2ビットを出力に設定


LED0のみ点灯


LED1のみ点灯


両LED点灯


消灯

注意

FFFC8はwrite onlyレジスタなので,読み出してもレジスタの内容を
読み出すことができない。したがって,モニタプログラムでFFFC8を
表示させても,表示されている値はレジスタの値とは異なる(ごみ値)

FFCAは下位4ビットのみ有効である。上位4ビットに値を書き込むこと
はできない。このレジスタの内容を読み出しても,上位4ビットは読
み出すことができず,モニタプログラムで表示しても上位4ビットは
不定値である。(ここでは上位4ビットに1が見えている)

次のプログラムは,P5DDRのbit0を出力に設定したのち,P5DRのbit0に向けて1と0を交互に出力する。

LED点滅プログラム

    .CPU 300HA

P5DDR .EQU H'FFFC8
P5DR  .EQU H'FFFCA

    .SECTION A,DATA,LOCATE=H'0FF030
    .DATA.L H'0FF130  ;リセットベクトル

    .SECTION P,CODE,LOCATE=H'0FF130
    MOV.L  #H'FFF00,ER7  ;スタックポインタ設定
    MOV.B #H'1, R1L      ; 00000001(2進数表現) を 8bitレジスタR1Lへ
    MOV.B R1L, @P5DDR    ; 8bitレジスタR1Lにある値をアドレスP5DDRへ
EternalLoop:
    MOV.B #H'1, R0L      ; 00000001(2進数表現) を 8bitレジスタR0Lへ
    MOV.B R0L, @P5DR     ; 8bitレジスタR0Lにある値をアドレスP5DRへ
    MOV.B #H'0, R0L      ; 00000000(2進数表現) を 8bitレジスタR0Lへ
    MOV.B R0L, @P5DR     ; 8bitレジスタR0Lにある値をアドレスP5DRへ
    BRA EternalLoop      ;永久ループ

    .END

このプログラムを実行形式にして,モニタプログラム上に読み込み,ステップ実行を続けると
LEDの点滅が見られる。
なお,.EQUというのは,C言語の#defineの働きをしている。プログラム本体に「P5DDR」
が出てきたら,それは「H'FFFC8」としてアセンブルしなさいの意味である。


課題3

上記のプログラムを動かして,LED0の点滅を確かめなさい。
次に,LED1が点滅するように書き換え動作させ,LED1の点滅を確かめなさい。
レポートには,実行の様子を貼り付け,どの位置で点灯し,消灯するのか示して,
考察しなさい。
P5DDRのアドレスが,0xFFFC8であるという記述をハードウェアマニュアルから見つけ,
そのページを考察に含めなさい。

(mon2ex03.txt)



(2)スイッチの状態取得
次に,LEDの点滅を8ビットDIPスイッチで制御してみよう。
8ビットスイッチは,ポート2(P2)に接続されている。

内部にはプルアップコントロールといって,プルアップ抵抗を介して電源につなげることを有効にする機能がある。

P2と呼んでいるポートの実体はメモリ空間に割り当てられているIOレジスタである。
8ビットスイッチの状態を取得するには,次の3つのことが必要である。取得対象はDIPSW0の1つだけとする。
(1)P2DDR(Data Direction Register)と呼ばれる入出力方向を設定するレジスタのbit0に,
   出力として使うという設定を行なう。このビットを0にすると入力設定となる。
   (このビットを1にすると出力設定となる)
(2)P2PCR(Pullup Control Register)と呼ばれるプルアップ制御を設定するレジスタのbit0に,
   プルアップ有効という設定を行なう。このビットを1にするとプルアップ有効設定となる。
   (このビットを0にするとプルアップ無効設定となる)
(3)P2DRは,CPUのピンの状態をそのまま汎用レジスタに入力するする8ビットのレジスタである。
   このレジスタのbit0に5Vを与えると1が,0Vを与えると0が入力される。

H8/3048のハードウェアマニュアルによれば,P2DDRはメモリ空間上の1byteのように見える。
P2DDRのアドレスは,0xFFFC1である。
同様にP2PCRもメモリ空間上の1byteのように見える。
P2PCRのアドレスは。0xFFFD8である。
同様にP2DRもメモリ空間上の1byteのように見える。
P2DRのアドレスは。0xFFFC3である。
これらのアドレスは,CPU設計時に決められているため,変更することはできない。



課題4

モニタプログラムのコマンドで,8ビットDIPスイッチのビット パタンを読み取れていることを確かめてみよう。
mコマンドで,fffc1に00を設定しP2を入力に設定する。
mコマンドで,fffd8にffを設定し,P2のプルアップコントロールを有効にする。
dコマンドで,fffc3を表示して8ビットDIPスイッチの状態と対応を考察しなさい。
8ビットDIPスイッチのON-OFFパタンを変化させて,
dコマンドで,fffc3を表示して8ビットDIPスイッチの状態と対応を考察しなさい。
さらに何回か8ビットDIPスイッチのON-OFFパタンを変化させながら,
dコマンドで,fffc3を表示して8ビットDIPスイッチの状態と対応を考察しなさい。

なお,fffc1はWriteOnlyレジスタなので,モニタプログラムで表示しても,その時のレジスタの 値を正しく
表示することはできない。

レポートでは,8ビットDIPスイッチの状態とfffc3の内容 の対応を5例ほど示しなさい。

(mon2ex04.txt)


(3)スイッチの状態取得とLED点滅

次のプログラムは,8ビットスイッチのSW0のON-OFFの状態を取り込み,それに対応して,
LED0を点灯あるいは消灯させる。

8ビットスイッチの状態取得とLED制御プログラム

    .CPU 300HA

P5DDR  .EQU H'FFFC8
P5DR   .EQU H'FFFCA
P2DDR  .EQU H'FFFC1
P2DR   .EQU H'FFFC3
P2PCR  .EQU H'FFFD8

    .SECTION A,DATA,LOCATE=H'0FF030
    .DATA.L H'0FF130  ;リセットベクトル

    .SECTION P,CODE,LOCATE=H'0FF130
    MOV.L  #H'FFF00,ER7  ;スタックポインタ設定
    MOV.B #H'1, R1L      ; 00000001(2進数表現) を 8bitレジスタR1Lへ
    MOV.B R1L, @P5DDR    ; 8bitレジスタR1Lにある値をアドレスP5DDRへ
    MOV.B #H'0, R1L      ; 00000000(2進数表現) を 8bitレジスタR1Lへ
    MOV.B R1L, @P2DDR    ; 8bitレジスタR1Lにある値をアドレスP2DDRへ
    MOV.B #H'1, R1L      ; 00000001(2進数表現) を 8bitレジスタR1Lへ
    MOV.B R1L, @P2PCR    ; 8bitレジスタR1Lにある値をアドレスP2PCRへ
EternalLoop:
    MOV.B @P2DR, R0L     ; アドレスP2DR を 8bitレジスタR0Lへ
    MOV.B R0L, @P5DR     ; 8bitレジスタR0Lにある値をアドレスP5DRへ
    BRA EternalLoop      ;永久ループ

    .END

このプログラムを実行形式にして,モニタプログラム上に読み込み,ステップ実行を続けると
8ビットスイッチのSW0のON-OFF状態に対応したLEDの点滅が見られる。



課題5

上記のプログラムを動かして,8ビットスイッチのSW0の変更と LED0の点滅を確かめなさい。
次に,8ビットスイッチのSW1に対応してLED1が点滅するように書き換え動作させ,LED1の点滅を確 かめなさい。
レポートには,実行の様子を貼り付け,8ビットスイッチSW1のON-OFF状態がどこでどのような値とし てとらえら
れているのか
,またLEDはどの位置で点灯し, 消灯するのか示して,考察しなさい。

(mon2ex05.txt)

 

7. 乗算・除算

2進数の掛け算はつぎのようなイメージである。
例 10110×1010=1101110

              10110    .
          ×   1010    .
             10110     .
           10110       .
           11011100    .

桁を省略せずに書くと次のようになる。

              10110       最初のr0 .
          ×   1010     . 最初のr1  s
             101100    左シフト中のr0
           10110000    .
  左シフト中のr0
           11011100    .  r2(最初は0,シフト中のr0を加算している)

アセンブリプログラムでの乗算は,シフト命令と加算命令で作ることができそうである。

この考え方をC言語で書いてみると次のようになる。

mult_PC.c

掛け算をシフトと足し算で行うCプログラム。これはPCで実行できる。

#include "stdio.h"

int main()
{
    int x00,x10;
    int x0,x1,x2; //x2=x0*r1を作る
    scanf("%d %d",&x00,&x10);

    x0=x00;
    x1=x10;
    x2=0;
    do {
        if(x1&1) x2+=x0;
        x0<<=1;
        x1>>=1;
    } while (x1);

    printf("x00,x10,x2=  %04x,  %04x,  %04x\n",x00,x10,x2);
    printf("x00,x10,x2=%6d,%6d,%6d\n",x00,x10,x2);
}

/*実行例
85 10
x00,x10,x2=  0055,  000a,  0352
x00,x10,x2=    85,    10,   850
*/
mult.c

掛け算Cプログラム(mult_PC.c)を次のように改めて,c2asm.cmd
でアセンブリプログラムに変換すると,カンニングができる。
グローバル変数はメモリに明示的に割り当てられ,オート変数は
レジスタに割り当てられる。
short int x00=0x55;
short int x10=0xa;
short int y0; /* x0=x00*x10 */

int main()
{
    short int x0,x1,x2;
    x0=x00;
    x1=x10;
    x2=0;
    do {
        if(x1&1) x2+=x0;
        x0<<=1;
        x1>>=1;
    } while (x1);
    y0=x2;
}

一方2進数の割り算は次のようなイメージである。
例 10110110÷1010=10010 余り 10

                10010     .
      1010 )10110110     .
             1010         .
                1011      .
                1010      .
                   10

桁を省略せずに書くと次のようになる。
最初はr0に10110110を,r1に1010を入れておく

                10010     . r2に答えが作られる (r2の初期値は0)
      1010 )10110110     . r0(最初の状態)
             10100000     .  r0を超えないように,r1を左シフトした
                10110     . r0(r1を引いたところ)
                10100     . r1を右シフト
                   10    あまりはr0に残る

アセンブリプログラムでの除算は,シフト命令とシフト命令と減算命令(CMP命令を用いると引くことができるかどうかわかる)で作ることができそうである。

割り算をシフトと引き算で行うCプログラム

#include "stdio.h"

int main()
{
    int x00,x10;
    int x0,x1,x2; //x0÷x1=x2 あまり x0を作る
    int x3;
    scanf("%d %d",&x00,&x10);

    x0=x00;
    x1=x10;
    x2=0;
    x3=1;
    while (x1<x0) {
        x1<<=1;
        x3<<=1;
    }
    while (x3!=0) {
        if(x1<=x0) {
            x0-=x1;
            x2+=x3;
        }
        x1>>=1;
        x3>>=1;
    }

    printf("x00,x10,x2,x0=  %04x,  %04x,  %04x,  %04x\n",x00,x10,x2,x0);
    printf("x00,x10,x2,x0=%6d,%6d,%6d,%6d\n",x00,x10,x2,x0);
}

/*実行例
135 10
x00,x10,x2,x0=  0087,  000a,  000d,  0005
x00,x10,x2,x0=   135,    10,    13,     5

1025 25
x00,x10,x2,x0=  0401,  0019,  0029,  0000
x00,x10,x2,x0=  1025,    25,    41,     0
*/
割り算Cプログラムを次のように改めて,前に使ったc2asm.cmd
でアセンブリプログラムに変換すると,カンニングができる。
グローバル変数はメモリに明示的に割り当てられ,オート変数は
レジスタに割り当てられる。

short int x00=0x87;
short int x10=0xa;
short int y0,y1; /* x00 div x10 = y1 ... y0 */

int main()
{
    short int x0,x1,x2,x3;
    x0=x00;
    x1=x10;
    x2=0;
    x3=1;
    while (x1<x0) {
        x1<<=1;
        x3<<=1;
    }
    while (x3!=0) {
        if(x1<=x0) {
            x0-=x1;
            x2+=x3;
        }
        x1>>=1;
        x3>>=1;
    }
    y1=x2;
    y0=x0;
}

 

参考 アセンブリ言語によるいくつかの条件ジャンプの例

          CMP.W       #12345:16,R0
          BLT         ABCD:8
R0 less than #12345:16 なら
ラベルABCD:へジャンプ
          CMP.W       R5,R0
          BGT         LOOP2:8
R0 grater than R5 なら
ラベルLOOP2へジャンプ
          MOV.W       E0,E0
          BNE         ZERO:8
E0 Not Equal 0 なら
ラベルZEROへジャンプ


Cプログラムをアセンブリプログラムに変換するツール
((本校)LANからのみ試用のためアクセスできる。)
4J電子計算機IIの授業ではこれを使う
c2asm.cmdにxxx.cをドロップすると,xxx.srcとxxx_1.srcが作成されるが,
xxx_1.srcはxxx.srcからコメント行を消去したものである。



課題6

1.テキストエディタとアセンブラを用いて次のプログラムを作成しな さい。
FF200から機械語プログラムを置きなさい。
FF800番地 - FF801番地に2バイトの値が,FF802番地 - FF803番地に2バイトの値があり,
それぞれ正の整数であるとして,この2数の積を求め,FF804番地 - FF805番地に保存するプログラム。
掛け算の結果がオーバーフローしても構わない。
ただしMULで始まる掛け算命令を用いてはならない。

プログラム本体および以下を報告しなさい。
プログラムが正しく動作していることを検証し,検証の様子も報告しなさい。
検証では2×3,0x22×0x33,0xaa×0xbbを行い,手計算の値と比較しなさい。
実行結果を貼り付けるだけでなく,まとめのところで実行検証結果についてまとめなさい。
(mon2ex06.txt)

  ヒント プログラムの骨組み
  MOV.L  #H'FFF00,ER7    ;スタックポインタ設定
  MOV.W  @H'FF800:24,R0  ;FF800番地の2byteの値をR0に
  MOV.W  @H'FF802:24,R1  ;FF802番地の2byteの値をR1に
       ((( R0×R1 → R2 )))
  MOV.W  R2,@H'FF804:24  ;R2の値をFF804番地に



作業例 そのまま動くとは限らないので,自己責任で活用すること ● リンク

2.テキストエディタと アセンブラを用いて次のプログラムを作成しなさい。
FF200から機械語プログラムを置きなさい。
FF800番地 - FF801番地に2バイトの値Aが,FF802番地 - FF803番地に2バイトの値Bがあ り,
それぞれ正の整数であるとして,この2数の商(A/B)と余り(A%B)を求め,
商をFF804番地 - FF805番地に,余りをFF806番地 - FF807番地
に保存するプログラム。
「(A - 余り)÷B=商」の関係をもつこと。
0による割り算は行わないものとする。
ただしDIVで始まる割算命令を用いてはならない。

プログラム本体および以下を報告しなさい。
プログラムが正しく動作していることを検証し,検証の様子も報告しなさい。
検証では3÷2,0x1000÷0x33,0xaaaa÷0xbbを行い,手計算の値と比較しなさい。
実行結果を貼り付けるだけでなく,まとめのところで実行検証結果についてまとめなさい。
(mon2ex07.txt)
●発展参考資料


3.テキストエディタとアセンブラを用いて次のプログラムを作成 しなさい。
FF200から機械語プログラムを置きなさい。
FF800番地 - FF801番地に2バイトの値が,FF802番地 - FF803番地に2バイトの値があり,
それぞれ整数であるとして,この2数の積を求め,FF804番地 - FF805番地に保存するプログラム。
値が正の数・負の数にかかわらず正しい答えを出すようにすること
掛け算の結果がオーバーフローしても構わない。
ただしMULで始まる掛け算命令を用いてはならな い。

プログラム本体および以下を報告しなさい。
プログラムが正しく動作していることを検証し,検証の様子も報告しなさい。
検証では0xaa×0xbb0xaa×(-0xbb),(-0xaa)×0xbb,(-0xaa)×(-0xbb)を行い,
手計算の値と比較しなさい。
実行結果を貼り付けるだけでなく,まとめのところで実行検証結果についてまとめなさい。
(mon2ex08.txt)
●発展参考資料


4.挑戦課題(挽回課題).テキストエディタとアセンブラを用 いて次のプログラムを作成しなさい。
FF200から機械語プログラムを置きなさい。
FF800番地 - FF801番地に2バイトの値Aが,FF802番地 - FF803番地に2バイトの値B があり,
それぞれ整数であるとして,この2数の商(A/B)と余り(A%B)を求め,
FF804番地 - FF805番地とFF806番地 - FF807番地
に保存するプログラム。
値が正の数・負の数にかかわらず「正の余り」を持ち,
「(A - 余 り)÷B=商」の関係をもつこと。
以下の例で検証しなさい。
11÷4 = 2...余り3
(-11)÷4 = -3...余り1
11÷(-4) = -2...余り3
(-11)÷(-4) = 3...余り1
0による割り算は行わないものとする。

ただしDIVで始まる割算命令を用いてはならない。

プログラム本体および以下を報告しなさい。
プログラムが正しく動作していることを検証し,検証の様子も報告しなさい。
(mon2ex09.txt)
●発展参考資料



課題7

1.テキストエディタとアセンブラを用いて次のプログラムを作成しなさい。
FF200から機械語プログラムを置きなさい。
C言語の関数インターフェイス(引数,関数の値の返し方)で2つのint型(2バイト)の引数2つを
受取り,課題6の1で作った掛け算を行い,関数の値として
int型(2バイト)の値を返すサブルーチン。
呼び出しルーチンも次のように作りなさい。
FF800番地 - FF801番地に2バイトの値が,FF802番地 - FF803番地に2バイトの値を引数に載 せ,
掛け算サブルーチンを呼び出し,この2数の積を求め,FF804番地 - FF805番地に保存する。


プログラム本体および以下を報告しなさい。
プログラムが正しく動作していることを検証し,検証の様子も報告しなさい。
検証では2×3,0x22×0x33,0xaa×0xbbを行い,手計算の値と比較しなさい。
実行結果を貼り付けるだけでなく,まとめのところで実行検証結果についてまとめなさい。
(mon2ex10.txt)

  ヒント1 C言語コンパイラでは,2つの引数はr0とr1に載せて関数を呼び出し,
     関数は戻り値をr0に載せて返すことになっている。
     c2asm.html(Cプログラムをアセンブリプログラムに変換)の
    「【6】関数呼び出し(2引数)と関数の戻り値」を参照しなさい

  ヒント2  プログラムの骨組み
    MOV.L  #H'FFF00,ER7    ;スタックポインタ設定
    MOV.W  @H'FF800:24,R0  ;FF800番地の2byteの値をR0に
    MOV.W  @H'FF802:24,R1  ;FF802番地の2byteの値をR1に
    jsr    @mymultfunc     ;jump subroutine
    MOV.W  R0,@H'FF804:24  ;R0の値をFF804番地に
    おわり(自分自身への無限ループ)

    mymultfunc:
         ((( R0×R1 → R2 )))
         ((( R2 → R0 )))
    rts   (retrun from subroutine)

2.テキストエディタと アセンブラを用いて次のプログラムを作成しなさい。
FF200から機械語プログラムを置きなさい。
C言語の関数インターフェイス(引数,関数の値の返し方)で2つのint型(2バイト)の引数2つを
受取り,課題6の2で作った割り算を行い,商だけを関数の値として返すサブルーチン。
(余りは返さない)
割り算は第1引数÷第2引数の演算とする。
呼び出しルーチンも次のように作りなさい。
FF800番地 - FF801番地に2バイトの値(割られる数)が,FF802番地 - FF803番地に2バイ トの値
(割る数)があるものとし,これらを引数に載せ,
割り算サブルーチンを呼び出し,この2数の商を求め,
サブルーチンが返してきた値をFF804番地 -  FF805番地に保存する。

プログラム本体および以下を報告しなさい。
プログラムが正しく動作していることを検証し,検証の様子も報告しなさい。
検証では3÷2,0x1000÷0x33,0xaaaa÷0xbbを行い,手計算の値と比較しなさい。
実行結果を貼り付けるだけでなく,まとめのところで実行検証結果についてまとめなさい。
(mon2ex11.txt)


 


8.参考(1) アッセンブルコマンド「Asm2Mon.cmd」

Asm2Mon.cmd

rem ------------------------------------------------------------------------
rem H8のモニタ上で実行する実習用ソースファイルからMOTファイルを作ります
rem H8Cコンパイラver2のセットに対応しています。
rem ASMのソースファイルのドラッグ&ドロップに対応
rem ------------------------------------------------------------------------

@echo off
echo Assemble, link and convert command for H8 ASM-programing with V2 ver1.00
echo Copyright(c) 29June2006 coskx
REM Copyright(c) 9Dec2002 coskx

rem カレントドライブ・カレントディレクトリへ移動
%~d1
cd %~p1

rem コンパイラのパスの設定
path=%path%;%HOMEDRIVE%\Program Files\h8v2\bin
set h8inc=%HOMEDRIVE%\Progra~1\h8v2\include
set h8lib=%HOMEDRIVE%\Progra~1\h8v2\lib

rem 誤ったファイルがドロップされたか,単なるダブルクリックで起動した場合は何もしない
if exist %~n1.src goto ASSEMBLE
if exist %~n1.mar goto ASSEMBLE
goto NO_SOURCE_ERROR

:ASSEMBLE
asm38 %~n1.src -so -cr -list
if not exist %~n1.obj goto ASM_ERROR

:LINK
rem ----------------------------------------------------------------------------
lnk %~n1 -PRINT=%~n1  >q9j2h5c4k6b1.txt
type q9j2h5c4k6b1.txt
find "**" q9j2h5c4k6b1.txt >nul
if errorlevel 1 goto CONVERT
del q9j2h5c4k6b1.txt
if exist %~n1.abs del %~n1.abs
goto LINK_ERROR

:CONVERT
del q9j2h5c4k6b1.txt
rem ----------------------------------------------------------------------------
rem Sフォーマットに変換 xxx.motの作成
cnvs %~n1.abs
del %~n1.abs
del %~n1.obj
ren %~n1.MOT %~n11.MOT
two2neg.exe <%~n11.MOT >%~n1.MOT
del %~n11.MOT

goto TERMINAL

:NO_SOURCE_ERROR
echo *** error *** ASMのソースファイルが指定されていません。
goto TERMINAL

:ASM_ERROR
echo *** error *** コンパイルエラーがありました。
goto TERMINAL

:LINK_ERROR
echo *** error *** リンクエラーです。
goto TERMINAL

:TERMINAL
echo Pushing any key leads the exit.
pause >nul
exit

 

9.参考(2)h8v2フォルダの構成例

h8v2の構成例
C:\Program Files\h8v2
├─BIN
│      ASM38.EXE
│      C38ASM.EXE
│      C38CGN.EXE
│      C38FRNT.EXE
│      C38MID.EXE
│      C38PEP.EXE
│      CH38.EXE
│      CNVS.EXE
│      h8v2cc.cmd
│      LNK.EXE
│      OPT38.EXE
│      OPTLNK38.EXE
│     
├─INCLUDE
│      3048F.H
│      3048FONE.H
│      3048S.H
│      3664S.H
│      ASSERT.H
│      CTYPE.H
│      ERRNO.H
│      FLOAT.H
│      INDIRECT.H
│      LIMITS.H
│      MACHINE.H
│      MATH.H
│      NO_FLOAT.H
│      SETJMP.H
│      STDARG.H
│      STDDEF.H
│      STDIO.H
│      STDLIB.H
│      STRING.H
│     
├─LIB
│  │  C38HA.LIB
│  │  C38HAS.LIB
│  │  C38HN.LIB
│  │  C38HNS.LIB
│  │  C38REG.LIB
│  │  C38REGS.LIB
│  │  C8S26A.LIB
│  │  C8S26AS.LIB
│  │  C8S26N.LIB
│  │  C8S26NS.LIB
│  │  start3048.OBJ
│  │  start3048I.OBJ
│  │ 
│