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

Copyright(C)29Dec2010
since 1Aug2003
coskx


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

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

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

このファイルを解凍すると「trial4」のフォルダが出てくるので,
作業用フォルダとして使います。
((本校)LANからのみ試用のためアクセスできます。)
4J電子計算機IIの授業ではこれを使います

H8機械語命令ニーモニクの説明マニュアル
((本校)LANからのみアクセスできます。)

注意
この文書で扱っているAsm2Mon.cmdはWindows2000,WindowsXP,WindowsVista,Windows7で使用可能です。

 

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

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

(1)アセンブリ言語で書かれたプログラム例
プログラムは次のようなものである。
 スタックポインタを初期化する(使わないのでしなくてもよい)
 FF800番地の2byteデータをレジスタR0に載せる
 FF802番地の2byteデータをレジスタR1に載せる
 R0とR1の値を加えてR0にしまう
 R0のデータをFF804番地にしまう
 ただしプログラム起動の時点で,
 FF800番地にはx1234,FF802番地にはx2345,FF804番地にはx3456が入っているものとする。

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


ベクタテーブル領域 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までにプログラムがあることがわかる

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

    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領域へのプログラム書き込みを行う。

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

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

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

teratermを用いた機械語プログラムの転送

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

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

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

この時のモニタ画面


: L


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

5)書き込み終了

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

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

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

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

この時のモニタ画面

: L

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

5)書き込み終了

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


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

内容 モニタ画面
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"
プログラムの確認
(ディスアセンブル)
: 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

(4)実行
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番地付近の
メモリ表示

: 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になっているときはこの作業は不要です。

 

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

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

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

内容 モニタ画面
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"
プログラムの確認
(ディスアセンブル)
: 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
ブレークポインタ
の設定
: 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の電源を落とすしかない

 

4. メモリ領域のフィル

例題1

アセンブラを用いて次のプログラムを作成しなさい。
FF200から機械語プログラムを置きなさい。
FF800番地〜FF83F番地メモリすべてに0x55を埋めなさい。
以下を報告しなさい。
実行前のFF800番地〜FF83F番地の様子
プログラムの逆アッセンブル結果
ブレークポイントを設定して実行した時の実行の様子
実行後のFF800番地〜FF83F番地の様子

アセンブリ
プログラム

    .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

RAM領域へ
プログラムを
転送後の
実行例
: 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 ff84f
  <ADDR>                  <  D  A  T  A  >                     < ASCII CODE >
  FF800   00 00 FF FF 00 00 FF FF  00 00 FF FF 00 00 FF FF   "................"
  FF810   00 00 FB FF 00 00 DF FF  00 02 FF FF 00 00 FF FF   "................"
  FF820   00 00 FF FF 00 00 FF FF  00 00 FF FF 01 00 FF FF   "................"
  FF830   42 00 FF FF 02 04 FE FF  08 04 ED FF 00 00 FF FD   "B..............."
  FF840   00 00 FF FF 00 00 FF FF  00 00 FF FF 00 00 FF FF   "................"
: .pc
  PC=0FF200  ?  ff200
  CCR=80  ?  .
: b ff218
: r
  PC=0FF200  CCR=80:I.......  SP=00FFFF10
  ER0=00000000  ER1=00000000  ER2=00000000  ER3=00000000
  ER4=00000000  ER5=00000000  ER6=00000000  ER7=00FFFF10
: 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   00 00 FF FF 00 00 FF FF  00 00 FF FF 00 00 FF FF   "................"
:

参考 

L001:
MOV.B r0l,@ER1 ;0x55をER1の指しているところへ
INC.L #1,ER1
DEC.B r0h
BNE L001:8 ; r0h!=0の場合はL12へジャンプ
ラベル L001



条件ジャンプ

行の1文字目から書かれる名前はラベルと呼ばれ,ジャンプ命令の行き先となる。
「BNE L001:8」直前の操作の結果が0でなかった(Not Equal to 0)らL001にジャンプ
ある条件が成り立ったらジャンプするという命令は条件ジャンプと呼ばれ,
C言語でいうところのif文の構造を作ったり,ループ構造を作ったりするのに必須の命
令である。
条件ジャンプは多くの種類があるため,命令マニュアルでは「Bcc」として一括して説
明されている。

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

課題1

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

プログラム本体および以下を報告しなさい。
(このプログラムの実行の効果がわかるように工夫すること)
実行前のFF800番地〜FFA0F番地の様子
プログラムの逆アッセンブル結果
ブレークポイントを設定して実行した時の実行の様子
実行後のFF800番地〜FFA0F番地の様子
(mon2ex01.txt)

ヒント 8bitのレジスタの扱うことのできる値の範囲は0〜255
ヒント dec命令では8bitレジスタに対する場合と16bit以上のレジスタに対する場合で
    書式が異なる

 

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

課題2

テキストエディタとアセンブラを用いて次のプログラムを作成しなさい。
FF200から機械語プログラムを置きなさい。
プログラムの行うべき作業
(1)FF800番地〜FF87F番地メモリすべてに0x80を埋めなさい。
(2)次にFF800番地〜FF87F番地のメモリの内容をFF900番地〜FF97F番地にコピーしなさい。

プログラム本体および以下を報告しなさい。
(このプログラムの実行の効果がわかるように工夫すること)
プログラム実行前のFF800番地〜FF98F番地の様子
プログラムの逆アッセンブル結果
ブレークポイントを設定して実行した時の実行の様子
実行後のFF800番地〜FF98F番地の様子
(mon2ex02.txt)

 

6. IOポート

ここでアセンブリプログラムによる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)


次に,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)

次のプログラムは,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 .
シフト命令と加算命令で作ることができそうである。
この考え方をC言語で書いてみると次のようになる。

掛け算をシフトと足し算で行うCプログラム

#include "stdio.h"

int main()
{
    short int r00,r10;
    short int r0,r1,r2; //r2=r0*r1を作る
    scanf("%d %d",&r00,&r10);

    r0=r00;
    r1=r10;
    r2=0;
    do {
        if(r1&1) r2+=r0;
        r0<<=1;
        r1>>=1;
    } while (r1);

    printf("r0,r1,r2= %04x, %04x, %04x\n",r00,r10,r2);
    printf("r0,r1,r2=%6d,%6d,%6d\n",r00,r10,r2);
}

/*実行例
85 10
r0,r1,r2= 0055, 000a, 0352
r0,r1,r2= 85, 10, 850
*/

一方2進数の割り算は次のようなイメージである。
例 10110110÷1010=10010 余り 10
10010 .
1010 )10110110 .
1010 .
1011 .
1010 .
10
シフト命令と減算命令(CMP命令を用いると引くことができるかどうかわかる)

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

#include "stdio.h"

int main()
{
    short int r00,r10;
    short int r0,r1,r2; //r0÷r1=r2 あまり r0を作る
    short int r3;
    scanf("%d %d",&r00,&r10);

    r0=r00;
    r1=r10;
    r2=0;
    r3=1;
    while (r1<r0) {
        r1<<=1;
        r3<<=1;
    }
    while (r3!=0) {
        if(r1<=r0) {
            r0-=r1;
            r2+=r3;
        }
        r1>>=1;
        r3>>=1;
    }

    printf("r00,r10,r2,r0=  %04x,  %04x,  %04x,  %04x\n",r00,r10,r2,r0);
    printf("r00,r10,r2,r0=%6d,%6d,%6d,%6d\n",r00,r10,r2,r0);
}

/*実行例
135 10
r00,r10,r2,r0=  0087,  000a,  000d,  0005
r00,r10,r2,r0=   135,    10,    13,     5

1025 25
r00,r10,r2,r0=  0401,  0019,  0029,  0000
r00,r10,r2,r0=  1025,    25,    41,     0
*/

 

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

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へジャンプ

 

課題6

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

プログラム本体および以下を報告しなさい。
プログラムが正しく動作していることを検証し,検証の様子も報告しなさい。
オーバーフローしない例を検証しなさい。
(mon2ex06.txt)

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

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

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

プログラム本体および以下を報告しなさい。
プログラムが正しく動作していることを検証し,検証の様子も報告しなさい。
オーバーフローしない例を検証しなさい。
(mon2ex08.txt)

挑戦課題(挽回課題).テキストエディタとアセンブラを用いて次のプログラムを作成しなさい。
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=-2...余り(-3)
11÷(-4)=-2...余り3
(-11)÷(-4)=2...余り(-3)
0による割り算は行わないものとする。

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

プログラム本体および以下を報告しなさい。
プログラムが正しく動作していることを検証し,検証の様子も報告しなさい。

課題7

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


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

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


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

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

参考 正負数掛け算プログラム

正負数掛け算のCプログラム

#include "stdio.h"

int main()
{
    short int r00,r10;
    short int r0,r1,r2; //r2=r0*r1を作る
    scanf("%d %d",&r00,&r10);

    r0=r00;
    r1=r10;
    r2=0;
    do {
        if(r1&1) r2+=r0;
        r0<<=1;
        r1>>=1;
        r1&=0x7fff;
    } while (r1);

    printf("r0,r1,r2=  %04x,  %04x,  %04x\n",(unsigned short)r00,(unsigned short)r10,(unsigned short)r2);
    printf("r0,r1,r2=%6d,%6d,%6d\n",r00,r10,r2);
}

/*実行結果
85 10
r0,r1,r2=  0055,  000a,  0352
r0,r1,r2=    85,    10,   850

85 -10
r0,r1,r2=  0055,  fff6,  fcae
r0,r1,r2=    85,   -10,  -850

-85 10
r0,r1,r2=  ffab,  000a,  fcae
r0,r1,r2=   -85,    10,  -850

-85 -10
r0,r1,r2=  ffab,  fff6,  0352
r0,r1,r2=   -85,   -10,   850
*/


 

 


7.参考(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 TNCT

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フォーマットに変換 〜.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

 

8.参考(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
│  │ 
│