第4章 基本的なアセンブリ言語プログラミング
1.アセンブリ言語プログラム(1)プログラムの例
アドレス 機械語 ラベル ニ-モニック コメント .INCLUDE sfr_r829.inc ;擬似命令 .SECTION PROGRAM, CODE ;擬似命令 0D000 .ORG 0D000H ;擬似命令 0D000 Start: 0D000 C706FE00 MOV.B #00000110b, p1_drr 0D004 C706E100 MOV.B #00000110b, p1 0D008 C706E300 MOV.B #00000110b, pd1 0D00C 7E8F0907 BCLR p1_1 0D010 7E8F0A07 BCLR p1_2 0D014 Loop: ;永久ループで 0D014 FEFF JMP Loop ;実行停止
.SECTION FIXVECTOR, ROMDATA ;擬似命令 0FFFC .ORG 0FFFCH ;擬似命令 0FFFC Reset: 0FFFC 00D0F00F .LWORD Start | 0FF00000h ;擬似命令 .END ;擬似命令 (2)プログラムの構成とアセンブル 授業で作るプログラムの部分 PC エミュレータ または書込み回路 アセンブリ言語で記述されたソースプログラム オブジェクトプログラム アセンブリ言語で記述された ソースプログラムをアセンブ ラでアセンブルをしてオブジ ェクトプログラム(機械語)に 変換する エミュレータ:プログラムを PC から MPU に書き込みができ,さらにプログラム実 行途中でメモリやレジスタの値を監視
4-2 1)ソースプログラム(ソースコード) プログラミング言語 で記述したプログラムのことで,機械語に 変換する前の のプログラム 2)オブジェクトプログラム(オブジェクトコード) ソースプログラムを アセンブル や コンパイル をして得られた 機械語 のプ ログラム 3)オペコード アセンブリ言語命令において 命令の動作 を表す部分 4)オペランド アセンブリ言語命令において 動作の対象 となる部分 5)ニーモニック オペコード と オペランド を用いて表したアセンブリ言語命令 6)ラベル アセンブリ言語プログラム中において アドレス を数値で指定する代わりに用いる 文字記号名。ラベル名はプログラマによって自由(アルファベット,数字,記号を用い る)に作成できる。ただし先頭文字はアルファベット。分岐命令やデータ転送命令など でアドレスを指定するときに用いる。 7)アセンブル アセンブリ言語プログラムを 機械語 に変換する作業 8)アセンブラ アセンブリ言語プログラムを機械語に変換する ソフトウェア 9)擬似命令 アセンブリ言語プログラムを,どのように機械語に変換するのかを, アセンブラ に 対して指示する命令で,直接,機械語には 変換されない 命令。CPU への命令ではない。
(3)メモリへのプログラムの入り方 プログラムメモリ アドレス 命令 0D000h C7 0D001h 06 0D002h FE 0D003h 00 0D004h C7 0D005h 06 0D006h E1 0D007h 00 0D008h C7 0D009h 06 0D00Ah E3 0D00Bh 00 0D00Ch 7E 0D00Dh 8F ・ ・ ・ 以降,同様にしてメモリに入っていく MOV.B #00000110b, p1_drr MOV.B #00000110b, p1 MOV.B #00000110b, pd1
4-4 2.アセンブリ言語プログラミングの基礎 次に示す基本的な命令について学び,アセンブリ言語プログラミングの基礎を学ぶ。 ■転送命令(MOV 命令):データをある場所(レジスタやメモリ)からある場所(レジス タやメモリ)へ転送する命令。命令中の書いた数値をレジスタやメモリに格納すること もできる。転送元のデータをソース,転送先のデータをディスティネーションと呼ぶ。 基本形 MOV.B ソース, ディスティネーション MOV.W ソース, ディスティネーション ソースとディスティネーションの組合せ例(下図) ■キャリーなし加算命令(ADD 命令):キャリーを加えない加算。(キャリーとは桁上げ のこと) 基本形 ADD.B ソース, ディスティネーション ADD.W ソース, ディスティネーション ソースとディスティネーションの組合せ例 レジスタ R0(R0H,R0L) R1(R1H,R1L) R2 R3 A0 A1 など データ プログラム CPU メモリ CPU MOV.B 8bit レジスタ ,8bit レジスタ MOV.W 16bit レジスタ ,16bit レジスタ MOV.B 8bit レジスタ, アドレス MOV.W 16bit レジスタ, アドレス MOV.B アドレス,8bit レジスタ MOV.W アドレス,16bit レジスタ MOV.B #IMM,8bit レジスタ MOV.W #IMM,16bit レジスタ
ADD.B 8bit レジスタ, 8bit レジスタ ADD.W 16bit レジスタ, 16bit レジスタ
など
ADD.B 8bit レジスタ, アドレス ADD.W 16bit レジスタ, アドレス ADD.B #IMM, 8bit レジスタ ADD.W #IMM, 16bit レジスタ
ラベルが用いられる
※上図は MOV 命令のソースとディスティネーションの組合せ の一部である。図に示してない組合せも存在する。
■ボローなし減算命令(SUB 命令):ボローを引かない減算。(ボローとは借りのこと) 基本形 SUB.B ソース,ディスティネーション SUB.W ソース,ディスティネーション ソースとディスティネーションの組合せ例 ■無条件分岐命令(JMP 命令):指定したアドレスに強制的にジャンプする。 基本形 JMP アドレス ★復習★ レジスタについて
16bit 8bit 8bit R0 R1 R2 R3 A0 A1 FB データレジスタ:R0,R1,R2,R3
SUB.B 8bit レジスタ,8bit レジスタ SUB.W 16bit レジスタ,16bit レジスタ
など SUB.B 8bit レジスタ,アドレス SUB.W 16bit レジスタ,アドレス SUB.B #IMM,8bit レジスタ SUB.W #IMM,16bit レジスタ R0H R0L R1H R1L R2R0 32bit R3R1 A1A0
4-6 例題1 数値のレジスタへの転送,レジスタ同士の加算と減算,無条件分岐 (1)【8bit データの場合】R0L に 100,R0H に 15,R1L に 61,R1H に 20 を格納してから, R0L+R1L+R0H-R1H を計算して R0L に求めなさい .ORG 0D000h ;① プログラムを格納する先頭アドレスを 0D000h とする MOV.B #100,R0L (1) ;② R0L ← 100 MOV.B #15,R0H (1) ;③ R0H ← 15 MOV.B #61,R1L (1) ;④ R1L ← 61 MOV.B #20,R1H (1) ;⑤ R1H ← 20 ADD.B R1L,R0L (2) ;⑥ R0L ← R0L + R1L ADD.B R0H,R0L (2) ;⑦ R0L ← R0L + R0H SUB.B R1H,R0L (3) ;⑧ R0L ← R0L – R1H Stop: JMP Stop (4) ;⑨ 実行停止 (2)【16bit データの場合】R0 に 10240,R1 に 4566,R2 に 12300 を格納してから,R0-R1+R2 を計算して R0 に求めなさい .ORG 0D000h ;①プログラムを格納する先頭アドレスを 0D000h とする MOV.W #10240,R0 (1) ;② R0 ← 10240 MOV.W #4566,R1 (1) ;③ R1 ← 4566 MOV.W #12300,R2 (1) ;④ R2 ← 12300 SUB.W R1,R0 (3) ;⑤ R0 ← R0 - R1 ADD.W R2,R0 (2) ;⑥ R0 ← R0 + R2 Stop: JMP Stop ;⑦ 実行停止
解説1
(1)数値をレジスタに転送する(転送命令) 【8bit データの場合】
MOV.B #IMM, 8bit レジスタ
オペレーション(動作)
#IMM → 8bit レジスタ(数値#IMM を 8bit レジスタに転送する) 例 1)MOV.B #5,R0L 2)MOV.B #0Ah,R0L 3)MOV.B #01110001b,R0L ※数値の書き方について他の命令も同じ形式(”#”を先頭につける)で書く ※数値を「即値」とか「イミディエートデータ」などと呼ぶ 【16bit データの場合】
MOV.W #IMM, 16bit レジスタ
オペレーション(動作)
#IMM → 16bit レジスタ(数値#IMM を 16bit レジスタに転送する) 例 1)MOV.W #10000,R0 2)MOV.W #0FFFFh,A1 3)MOV.W #1100001001110001b,R1 R0L,R0H,R1L,R1H 数値(”#”を先頭につける) 2 進数は数値の右に”b”を,16 進数は 数値の右に”h”を,10 進数は数値の右 に何もつけない 8bit データを扱うので“B”を指定 R0,R1,R2,R3,A0,A1 数値(”#”を先頭につける) 2 進数は数値の右に”b”を,16 進数は 数値の右に”h”を,10 進数は数値の右 に何もつけない 16bit データを扱うので“W”を指定
4-8
(2)レジスタ同士を加算する(キャリーなし加算命令) 【8bit データの場合】
ADD.B 8bit レジスタ①, 8bit レジスタ②
オペレーション(動作)
8bit レジスタ② ← 8bit レジスタ② + 8bit レジスタ① 例
1)ADD.B R0L,R1H 2)ADD.B R1L,R1H
3)ADD.B R1H,R1H
【16bit データの場合】
ADD.W 16bit レジスタ①, 16bit レジスタ②
オペレーション(動作)
16bit レジスタ② ← 16bit レジスタ② + 16bit レジスタ① 例 1)ADD.W R0,R1 2)ADD.W A1,A0 3)ADD.W R1,R1 R0L,R0H,R1L,R1H R0L,R0H,R1L,R1H 8bit データを扱うので“B”を指定 16bit データを扱うので“W”を指定 R0,R1,R2,R3,A0,A1 R0,R1,R2,R3,A0,A1
(3)レジスタ同士を減算する(ボローなし減算命令)
【8bit データの場合】
SUB.B 8bit レジスタ①, 8bit レジスタ②
オペレーション(動作)
8bit レジスタ② ← 8bit レジスタ② - 8bit レジスタ① 例
1)SUB.B R0L,R1H 2)SUB.B R1L,R1H
3)SUB.B R1H,R1H
【16bit データの場合】
SUB.W 16bit レジスタ①, 16bit レジスタ②
オペレーション(動作)
16bit レジスタ② ← 16bit レジスタ② - 16bit レジスタ① 例 1)SUB.W R0,R1 2)SUB.W A0,A1 3)SUB.W R1,R1 R0L,R0H,R1L,R1H R0L,R0H,R1L,R1H 8bit データを扱うので“B”を指定 16bit データを扱うので“W”を指定 R0,R1,R2,R3,A0,A1 R0,R1,R2,R3,A0,A1
4-10 (4)無条件分岐命令(無条件ジャンプ命令) JMP label ※label(ラベル)とはアセンブリ言語プログラムにおいて,ジャンプ先な どのプログラム中の位置を表すもので,プログラマが任意の文字列(アル ファベット・数字)を使ってラベルを作る。機械語に変換される際に,ラ ベルは自動的にアドレス値に変換される。 オペレーション(動作) PC ← label のアドレス (label の示すアドレスにジャンプし,そこから実行をする。) 例 1) Stop: JMP Stop 2) Loop: JMP Loop ジャンプ先のアドレスをラベルで記す 何らかの繰り返したい処理 (永久ループになる)
例題2 レジスタ間同士のデータ転送 (1)【8bit データの場合】R0L に 5 を格納してから,R0L の値を R0H,R1L,R1H にコピーを しなさい .ORG 0D000h ;① プログラムを格納する先頭アドレスを 0D000h とする MOV.B #5,R0L ;② R0L ← 5 MOV.B R0L,R0H (1) ;③ R0H ← R0L MOV.B R0L,R1L (1) ;④ R1L ← R0L MOV.B R0L,R1H (1) ;⑤ R1H ← R0L Stop: JMP Stop ;⑥ 実行停止 (2)【16bit データの場合】R0 に 10000 を格納してから,R0 の値を R1,R2,R3,A0,A1 にコ ピーをしなさい .ORG 0D000h ;① プログラムを格納する先頭アドレスを 0D000h とする MOV.W #10000,R0 ;② R0 ← 10000 MOV.W R0,R1 (1) ;③ R1 ← R0 MOV.W R0,R2 (1) ;④ R2 ← R0 MOV.W R0,R3 (1) ;⑤ R3 ← R0 MOV.W R0,A0 (1) ;⑥ A0 ← R0 MOV.W R0,A1 (1) ;⑦ A1 ← R0 Stop: JMP Stop ;⑧ 実行停止
4-12
解説2
(1)レジスタ間同士のデータ転送(転送命令) 【8bit データの場合】
MOV.B 8bit レジスタ①, 8bit レジスタ②
オペレーション(動作) 8bit レジスタ② ← 8bit レジスタ① 例 1)MOV.B R0L,R1H 【16bit データの場合】
MOV.W 16bit レジスタ①, 16bit レジスタ②
オペレーション(動作) 16bit レジスタ② ← 16bit レジスタ① 例 1)MOV.W R0,R1 2)MOV.W A0,R1 3)MOV.W A1,A0 R0L,R0H,R1L,R1H 8bit データを扱うので“B”を指定 R0L,R0H,R1L,R1H 16bit データを扱うので“W”を指定 R0,R1,R2,R3,A0,A1 R0,R1,R2,R3,A0,A1
プログラムリストはオペコード,オペランドの縦の列を揃えて書くこと。 問1 64+48+16 を計算するプログラム作れ。ただし例題1(1)をまねてプログラムせよ。 問2 200+34-116-44 を計算するプログラム作れ。ただし例題1(1)をまねてプログラ ムせよ。 問3 問1のプログラムで数値を 2 進数で指定する場合はどのようにすればよいか。問1のプ ログラムで変更すべき行とそれを変更した後の行について示しなさい。 問4 問1のプログラムで数値を 16 進数で指定する場合はどのようにすればよいか。1のプ ログラムで変更すべき行とそれを変更した後の行について示しなさい。 問5 14500+2040-20+6245-555 を計算するプログラム作れ。ただし例題1(2)をまね てプログラムせよ。(すべて 16bit データとして扱えばよい) 問6 R0L,R0H,R1L,R1H をすべて 0 にクリアするプログラム作れ。 問7 R0,R1,R2,R3,A0,A1 をすべて 0 にクリアするプログラム作れ。 問8 R0L に 10,R0H に 20,R1L に 30 を入れておき,R0L の内容を R0H に移動,R0H の内容を R1L に移動,R1L の内容を R0L に移動するプログラム作れ。 問9 R0 に 10000,R1 に 20000 を入れておき,R0 の内容と R1 の内容を交換するプログラム 作れ。
4-14
3.アセンブリ言語プログラミングの基礎 (I/O 操作)
ここでは,I/O に関する操作およびアセンブリ言語プログラミングの基礎について学び,ア センブラプログラミングによってマイコンに接続した外部機器とのデータ入出力方法の基礎 を習得する。
I/O は,第 3 章において述べた SFR(Special Function Register)にデータを読み書き することで,入出力方向や機能を決定したり,外部とのデータの入出力を行うことができる。 SFR は「レジスタ」と名付けられているが,実際は R8C のメモリアドレス 00000h~002FFh 番地に配置されており,メモリと同様な扱い方でデータの移動ができる。SFR には多くのレジ スタがあり,その一覧表は第 3 章の最後に載せてある。この一覧表のように SFR にはメモリア ドレスが割り当てられているので,基本的に転送命令(MOV 命令)を用いて SFR のアドレスを指 定し,SFR にデータを読み書きすることで I/O に設定をしたりデータを入出力したりすること ができる。ただし,実際にプログラミングする際に,SFR のアドレスは第 3 章の最後に載せて ある一覧表の「シンボル」を使用する。
例題3 【回路図1】DIP-SW の 1~4 と LED の 1~4 の順番を対応させて考える。ON になった DIP-SW の bit 位置に対応する LED を点灯し,OFF になった DIP-SW の bit 位置に対応する LED を消灯しなさい。(回路図1の SW は SW-OFF で「1」(5V),SW-ON で「0」(0V)がマイコンに 入力できる。また,LED はマイコンから「1」(5V)を出力すると消灯,「0」(0V)を出力する と点灯する。) .ORG 0D000h ; ①次のプログラムを格納する先頭アドレスを 0D000h とする MOV.B #00000000B,p1drr(4); ②p1drr(ポート p1 駆動能力制御レジスタ) ← すべて Low にしている MOV.B #11110000B,p1(2) ; ③p1(ポート p1) に初期出力データをセット MOV.B #11110000B,pd1(3) ; ④pd1(ポート p1 方向レジスタ) に入出力方向を設定。1:出力,0:入力。 この例の場合,P1 の上位 4bit が出力用に,下位 4bit が入力用に設定。 Loop: MOV.B p1(2),R0L ;⑤ R0L ← p1(ポート1から DIP-SW の値を入力) SHL.B #4,R0L (8);⑥ R0L を 4 回左シフト(下位 4bit のデータを上位 4bit に移動) MOV.B R0L,p1(2) ;⑦ p1(ポート1)← R0L。(入力に設定した bit には出力されない) JMP Loop ;⑧ ラベル Loop から繰り返す ※補足
MOV.B #00000000B,p1drr は,MOV.B #0,p1drr または MOV.B #00H,p1drr でも可。 MOV.B #11110000B,p1 は, MOV.B #240,p1 または MOV.B #0F0H,p1 でも可。 MOV.B #11110000B,pd1 は, MOV.B #240,pd1 または MOV.B #0F0H,pd1 でも可。
I/O ポート制御関係の SFR のアドレスを示すシンボル。これらのシンボルはアセンブラが自動的に 各 SFR のアドレスに置き換えてアセンブルする。I/O 関係の SFR のアドレスを示すシンボルは, p1,p3,p4,pd1,pd3,pd4,p1drr があるが,詳しくは第 3 章最後の一覧表を参照せよ。
【回路図
1
】
4-16 ■ポート p1 レジスタ”p1”, ポート p3 レジスタ”p3”,ポート p4 レジスタ”p4” ・・・I/O へ入出力するデータの受け渡し窓口となる SFR ■ポート p1 方向レジスタ”pd1”, ポート p3 方向レジスタ”pd3”,ポート p4 方向レジスタ”pd4” ・・・I/O ポートの各ビットごとに入出力方向を設定するための SFR ■ポート p1 駆動能力制御レジスタ”p1drr” ・・・ポート p1 の最大入出力電流を設定するための SFR(ポート p1 のみ最大入出力電流を変更できる)
4-18 解説3 (1)R8C/29 の I/O ポートの構成 ① R8C/29 には I/O ポートとしてポート p1,ポート p3,ポート p4 の 3 ポートがある。 ② ポート p1 には 8 本(p1_7,p1_6,p1_5,p1_4,p1_3,p1_2,p1_1,p1_0)が ある。入出力が可能であり,入出力方向をポート p1 方向レジスタ pd1 に設定デー タを書き込むことにより入出力方向をプログラムすることができる。 ③ ポート p3 には 4 本(p3_7,p3_5,p3_4,p3_3)がある。入出力が可能であり, 入出力方向をポート p3 方向レジスタ pd3 に設定データを書き込むことにより入出 力方向をプログラムすることができる。 ④ ポート p4 には 4 本(p4_7,p4_6,p4_5,p4_2)がある。p4_7 と p4_6 と p4_2 は入力専用である。p4_5 のみ入出力が可能であり,p4_5 は入出力方向をポート p4 方向レジスタ pd4 に設定データを書き込むことにより入出力方向をプログラム することができる。ただし,外部クロックを R8C/29 に接続する場合,p4_7 と p4_6 の端子はクロック入力端子(XOUT,XIN)として使われるため p4_7 と p4_6 は I/O ポートとして使用できない。 ⑤ 通常は,どのポートも入出力電流は 5mA となっている。 ⑥ ポート p1 の 8 本のみ,ポート 1 駆動能力制御レジスタ p1drr に設定データを書き 込むことにより LED 駆動ポートとして最大 15mA の駆動電流を流すことができるよ うになる。 (2)I/O ポートにデータを入出力をする SFR ① ポート p1 レジスタ“p1” ポート p1 のデータを入出力するレジスタである。p1_7~p1_0 にデータを書き込 むと,出力モードに設定された p1 の各 bit からそのデータを出力できる。また, p1_7~p1_0 にデータを読み込むと,入力モードに設定された p1 の各 bit からデ ータ入力ができる。 ② ポート p3 レジスタ“p3” ポート p3 のデータを入出力するレジスタである。p3_7,p3_5~p3_3 にデータを 書き込むと,出力モードに設定された bit からそのデータを出力できる。また, p3_7,p3_5~p3_3 からデータを読み込むと,入力モードに設定された bit からデ ータ入力ができる。
bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0 p1 p1_7 p1_6 p1_5 p1_4 p1_3 p1_2 p1_1 p1_0
bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0 p3 p3_7 0 p3_5 p3_4 p3_3 0 0 0
③ ポート p4 レジスタ“p4” ポート p4 のデータを入出力するレジスタである。p4_5 が出力モードに設定されて いるときは,pd4_5 にデータを書き込むとそのデータを出力できる。また,入力モ ードに設定された p4_5 または入力専用の p4_7 と p4_6 と p4_2 からデータを読み 込むとデータ入力ができる。なお,p4_7 と p4_6 と p4_2 は入力専用である。 ※プログラムでデータを入出力する方法 例 1)R0L からポート p1 に出力 MOV.B R0L,p1 2)数値 00110011B をポート p1 へデータを出力 MOV.B #00110011B,p1 3)ポート p1 の p1_5 のみに”1”を出力 BSET p1_5 (ビットセット命令) 4)ポート p1 の p1_4 のみに”0”を出力 BCLR p1_4 (ビットクリア命令) 5)ポート p1 から R0L にデータを入力 MOV.B p1,R0L 6)ポート p1 の p1_2 が”0”なのか,”1”なのかを確かめる BTST p1_2 (ビットテスト命令) ➢ もし p1_2=”0”ならばフラグ C=0,Z=1 となる ➢ もし p1_2=”1”ならばフラグ C=1,Z=0 となる (3)I/O ポートの入出力方向を設定する SFR ① ポート p1 方向レジスタ“pd1” ポート p1 の各 bit の入出力方向を設定するレジスタである。pd1_7~pd1_0 に”0” または”1”をセットして各 bit ごとに入出力方向を設定をする。 0:入力モード,1:出力モード ② ポート p3 方向レジスタ“pd3” ポート p3 の各 bit の入出力方向を設定するレジスタである。pd3_7,pd3_5~pd3_3 に”0”または”1”をセットして入出力方向を設定をする。bit6 および bit2~bit0 は未使用のため”0”をセットしておく。
bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0 p4 p4_7 p4_6 p4_5 0 0 p4_2 0 0
bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0 pd1 pd1_7 pd1_6 pd1_5 pd1_4 pd1_3 pd1_2 pd1_1 pd1_0
bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0 pd3 pd3_7 0 pd3_5 pd3_4 pd3_3 0 0 0
4-20 ③ ポート p4 方向レジスタ“pd4” ポート p4 の各 bit の入出力方向を設定するレジスタである。pd4_5 に”0”また は”1”をセットして入出力設定をする。bit4~bit0 は未使用のため”0”をセットし ておく。また,pd4_7 と pd4_6 と pd4_2 は入力専用のため”0”をセットしておく。 0:入力モード,1:出力モード ※プログラムで入出力方向を設定する方法 例 1)ポート p1 の p1_7~p1_5 を入力に,p1_4~p1_0 を出力に設定 MOV.B #00011111B,pd1 2)ポート p3 の pd3_7 を出力に,p3_5~p3_3 を入力に設定 MOV.B #10000000B,pd3 (4)ポート p1 の駆動能力(最大電流)を設定する SFR ① ポート p1 駆動能力制御レジスタ“p1drr” ポート p1 の p1_7,p1_6,p1_5,p1_4,p1_3,p1_2,p1_1,p1_0 の電流の駆動 能力を設定するレジスタである。p1drr7~p1drr0 に”0”または”1”をセットして駆 動能力を設定する。 0:駆動能力 LOW(5mA),1:駆動能力 HIGH(15mA) ※プログラムで駆動能力を HIGH に設定する方法 例 1)ポート p1 の p1_3 および p1_2 を駆動能力 HIGH に設定 MOV.B #00001100B,p1drr 注意:本書では LED を使用する場合でも,駆動能力は LOW に設定している。 bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0
pd4 pd4_7 pd4_6 pd4_5 0 0 pd4_2 0 0
bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0 p1drr p1drr7 p1drr6 p1drr5 p1drr4 p1drr3 p1drr2 p1drr1 p1drr0
(5)プログラム上の 1Byte 数値データをメモリ空間に転送する(転送命令) MOV.B #IMM,abs16 オペレーション(動作) abs16 で指定したアドレスのメモリ ← #IMM 例 1)MOV.B #000011111B,p1drr 数値 45 を p1drr 番地のメモリ空間に転送 2)MOV.B #0ah,p1 数値 10 をラベル p1 番地のメモリ空間に転送 (6)メモリ空間の 1Byte データをレジスタに転送する(転送命令)
MOV.B abs16, 8bit レジスタ
オペレーション(動作) 8bit レジスタ ← abs16 で指定したアドレスのメモリ空間の値 例 1)MOV.B p1, R0H メモリ空間 p1 番地の値を R0H に転送 (7)8bit レジスタの値をメモリ空間に転送する(転送命令)
MOV.B 8bit レジスタ, abs16
オペレーション(動作) abs16 で指定したアドレスのメモリ空間 ← 8bit レジスタの値 例 8bit データを扱うので“B”を指定 16bit のアドレス値。 プログラム時にはラベルを使用する。 数値データ(”#”を先頭につける) 2 進数は数値の右に”b”を,16 進数は数値の右に”h”を,10 進 数は数値の右に何もつけない 8bit データを扱うので“B”を指定 16bit のアドレス値。プログラム時にはラベルを使用する。 R0L,R0H,R1L,R1H 8bit データを扱うので“B”を指定 16bit のアドレス値。プログラム時にはラベ ルを使用する。 R0L,R0H,R1L,R1H
4-22
(8)データを指定された bit 数分,左または右にシフトする(論理シフト命令) SHL.B #IMM,8bit レジスタ
オペレーション(動作)
#IMM に指定した回数だけ,8bit レジスタの値を bit シフトする。ただし,#IMM<0 のときは右方向に,また#IMM>0 のときは左方向にシフトする。レジスタからあふ れた bit は C フラグに入る。 #IMM<0 のとき #IMM>0 のとき 例 1)SHL.B #2,R0L ➢ R0L を 2bit 左シフトする。 ➢ 仮に実行前:R0L=01011011,C=0 ならば,実行後:R0L=01101100,C=1 2)SHL.B #-3,R0H ➢ R0H を 3bit 右シフトする。 ➢ 仮に実行前:R0H=01011011,C=0 ならば,実行後:R0H=00001011,C=0 応用 左シフト 1 回は,2 倍したことと等価である。 右シフト 1 回は,1/2 倍したことと等価である。 MSB LSB 0 C MSB LSB C 0
問10 次のアセンブラ命令を示しなさい (1)p1_7,p1_6 ,p1_2,p1_1 を入力モードに, p1_5,p1_4,p1_3,p1_0 を出力モード に設定する (2)p3_7 を出力モードに,p3_5~p3_3 を入力モードに設定する (3)p4_5 を出力モードに設定する (4)p1_2,p1_1 の駆動能力を HIGH に設定する (5)ポート p3 から R1L に入力する (6)R0H からポート p3 に出力する
問11 【回路図1】DIP-SW の 1~4 と LED の 1~4 の順番を対応させて考える。ON になった DIP-SW の bit 位置に対応する LED を消灯し,OFF になった DIP-SW の bit 位置に対応する LED を点灯しなさい。ただし,プログラムは永久ループの構造にする。
問12 【回路図1】DIP-SW の ON 状態を”0”,OFF 状態を”1”と見立てる。DIP-SW の 1 を LSB, DIP-SW の 4 を MSB としてできる 4bit の 2 進数を考える。この 2 進数に 2 を加算して LED の 1~4 に表示しなさい。ただし LED1 を LSB,LED4 を MSB とし,2 進数の”1”は点灯,”0”は消 灯とする。プログラムは永久ループの構造にする。
問13 【回路図1】DIP-SW の ON 状態を”0”,OFF 状態を”1”と見立てる。DIP-SW の 1 を LSB, DIP-SW の 4 を MSB としてできる 4bit の 2 進数を考える。この 2 進数から 3 を減算して LED の 1~4 に表示しなさい。ただし LED1 を LSB,LED4 を MSB とする,2 進数の”1”は点灯,”0” は消灯とする。プログラムは永久ループの構造にする。
4-24
例題 4 【回路図1】DIP-SW の 1~4 と LED の 1~4 の順番を対応させて考える。押しボタン スッチ SW1 が押されて ON になったときに DIP-SW の状態を入力し,DIP-SW が ON になってい る bit 位置に対応する LED を点灯,OFF になっている bit 位置に対応する LED を消灯し続け なさい。 .ORG 0D000h ;① 次のプログラムを格納する先頭アドレスを 0D000h とする MOV.B #00000000B,p1drr ;② p1drr(ポート p1 駆動能力制御レジスタ) ← すべて Low にする MOV.B #11110000B,p1 ;③ p1(ポート p1) に初期出力データをセット MOV.B #11110000B,pd1 ;④ pd1(ポート p1 方向レジスタ) に入出力方向を設定。1:出力,0:入力 MOV.B #00000000B,pd3 ;⑤ pd3(ポート p3 方向レジスタ) に入出力方向を設定。1:出力,0:入力 Loop: BTST p3_3 (2);⑥ SW1 の ON/OFF チェック。p3_3 が 1 (つまり SW1:OFF)で,C=1 となる JC OWARI(1-1) ; ⑦上記⑧の結果 C=1 (つまり SW1:OFF) ならば⑩をジャンプして出力しない MOV.B p1,R0L ; ⑧ R0L ← p1。ポート1から R0L に入力 SHL.B #4,R0L ; ⑨R0L を 4 回左シフト MOV.B R0L,p1 ;⑩ p1(ポート1)← R0L。(入力に設定した bit には出力されない) OWARI: JMP Loop ;⑪Loop から繰り返す 解説4 (1-1)条件分岐(この例題4に使用している。 C フラグ=1 でジャンプする) JC label オペレーション(動作) C フラグ=0 のとき … ジャンプしないで次の命令を実行する C フラグ=1 のとき … label の番地へジャンプする 例 1)Start: 命令 1 命令 2 : : BTST p3_3 JC Start : ジャンプ先のアドレスをラベルで記す (ただし,PC-127≦label≦PC+128) C フラグ(キャリーフラグ) フラグレジスタの中の何種類かのフ ラグのうちの1つのフラグ。サイズは 1bit で 0 か 1 かの値を持つ。 ビットテスト命令(BTST 命令),比 較命令(CMP 命令)および演算命令な どにおいて,結果に応じて C フラグが 変化する。 C フラグ
(1-2)条件分岐(この例題4には使用していない。 C フラグ=0 でジャンプする) JNC label オペレーション(動作) C フラグ=0 のとき … label の番地へジャンプする C フラグ=1 のとき …ジャンプしないで次の命令を実行する 例 1)Start: 命令 1 命令 2 : : BTST p3_3 JNC Start : (1-3)条件分岐 (Z フラグ=1 でジャンプする。この例題4には使用していない) JZ label オペレーション(動作) Z フラグ=0 のとき … ジャンプしないで次の命令を実行する Z フラグ=1 のとき … label の番地へジャンプする 例 1) Start: 命令 1 命令 2 : : BTST p3_3 JZ Start : ジャンプ先のアドレスをラベルで記す (ただし,PC-127≦label≦PC+128) ジャンプ先のアドレスをラベルで記す (ただし,PC-127≦label≦PC+128)
4-26 (1-4)条件分岐(Z フラグ=0 でジャンプする。この例題4には使用していない) JNZ label オペレーション(動作) Z フラグ=0 のとき … label の番地へジャンプする Z フラグ=1 のとき … ジャンプしないで次の命令を実行する 例 1)Start: 命令 1 命令 2 : : BTST p3_3 JNZ Start : (2)指定した bit が“0”か“1”かをテストする (ビットテスト命令) BTST bit シンボル オペレーション(動作) bit シンボルの示す bit が“1”ならば,C=1,Z=0 となる。 bit シンボルの示す bit が“0”ならば,C=0,Z=1 となる。 例 1)p1_5 が”1“ならば Loop へジャンプする。 BTST p1_5 JC Loop または BTST p1_5 JNZ Loop 2)p4_7 が”0“ならば Loop へジャンプする。 BTST p4_7 JNC Loop または BTST p4_7 JZ Loop p1_7,p1_6,p1_5,p1_4,p1_3,p1_2,p1_1,p1_0 などの,解説 3の(2)~(4)に述べた各 SFR の bit シンボル ジャンプ先のアドレスをラベルで記す (ただし,PC-127≦label≦PC+128) Z フラグ フラグレジスタの中の何種類かのフ ラグのうちの1つのフラグ。サイズは 1bit で 0 か 1 かの値を持つ。 ビットテスト命令(BTST 命令),比 較命令(CMP 命令)および演算命令な どにおいて,結果に応じて Z フラグが 変化する。
例題5 【回路図1】DIP-SW の 1~4 と LED の 1~4 の順番を対応させて考える。SW1 が ON になったときの DIP-SW の状態を入力し,DIP-SW が ON になっている bit 位置に対応する LED を点灯,OFF になっている bit 位置に対応する LED を消灯し続けなさい。また,SW2 が ON に なったときの DIP-SW の状態を入力し,DIP-SW が ON になっている bit 位置に対応する LED を 消灯,OFF になっている bit 位置に対応する LED を点灯し続けなさい。
.ORG 0D000h ;① 次のプログラムを格納する先頭アドレスを 0D000h とする MOV.B #00000000B,p1drr ;②p1drr(ポート p1 駆動能力制御レジスタ) ← すべて Low にする MOV.B #11110000B,p1 ;③p1(ポート p1) に出力初期データをセット MOV.B #11110000B,pd1 ;④pd1(ポート p1 方向レジスタ) に入出力方向を設定。1:出力,0:入力 MOV.B #00000000B,pd3 ;⑤pd3(ポート p3 方向レジスタ) に入出力方向を設定。1:出力,0:入力 Loop: BTST p3_3 ;⑥ SW1 の ON/OFF チェック。p3 の bit3 が 1 ならば C=1 となる JC SW2_CHK ;⑦ C=1 (つまり SW1:OFF) ならば SW2 のチェックにジャンプ MOV.B p1,R0L ; ⑧ R0L ← p1。ポート1から入力 SHL.B #4,R0L ; ⑨ R0L を 4 回左シフト MOV.B R0L,p1 ;⑩ p1(ポート1)← R0L。(入力に設定した bit には出力されない) JMP OWARI ;⑪ 処理の終わりへ SW2_CHK: BTST p3_4 ;⑫ SW2 の ON/OFF チェック。p3 の bit4 が 1 ならば C=1 となる JC OWARI ;⑬ C=1 (つまり SW2:OFF) ならば終わりへジャンプ MOV.B p1,R0L ; ⑭ R0L ← p1。ポート1から入力 SHL.B #4,R0L ; ⑮ R0L を 4 回左シフト NOT.B R0L(1) ;⑯ R0L を反転 MOV.B R0L,p1 ;⑰ p1(ポート1)← R0L。(入力に設定した bit には出力されない) OWARI: JMP Loop ;⑱ 繰り返し 解説5 (1)8bit レジスタの各 bit の”0”,”1” を反転する (ビット反転命令) NOT.B 8bit レジスタ オペレーション(動作) 8bit レジスタ → 8bit レジスタ 例 NOT.B R0L 実行前:R0L=10101010B ”0”,”1” を反転 実行後:R0L=01010101B R0L,R0H,R1L,R1H
4-28 問14 【回路図1】 SW1 が押されたら LED を●○●○のパターンに点灯させ,SW2 が押され たら LED を○●○●のパターンに点灯させよ。ただし○は点灯,●は消灯とする。また,SW1 と SW2 の同時押しは禁止されているものとする。LED はプログラム動作開始時に全部消灯して おく。プログラムは永久ループの構造にする。 問15 【回路図1】 SW1 と SW2 が押されていないときは LED を○●●○のパターンに,SW1 が押されている間は LED を●●○○のパターンに,SW2 が押されている間は LED を○○●●の パターンに点灯させ続けよ。ただし○は点灯,●は消灯とする。また,SW1 と SW2 の同時押し は禁止されているものとする。プログラムは永久ループの構造にする。 問16 【回路図1】 SW1 を押した度に,押した回数を LED に表示しなさい。ただし LED1 を LSB,LED4 を MSB とし,2 進数の”1”は点灯,”0”は消灯とする。プログラム動作時は,0000B を LED に表示する。プログラムは永久ループの構造にする。
例題6 問16のスイッチ入力をソフトでチャタリング処理をするプログラムに変更せよ 問16【回路図1】 SW1 を押した度に,押した回数を LED に表示しなさい。ただし LED1 を LSB, LED4 を MSB とし,2 進数の”1”は点灯,”0”は消灯とする。プログラム動作時は,0000B を LED に表示する。プログラムは永久ループの構造にする。 .ORG 0D000h ;①次のプログラムを格納する先頭アドレスを 0D000h とする MOV.B #00000000B, p1drr ;②p1drr(ポート p1 駆動能力制御レジスタ) ← すべて Low にする MOV.B #11110000B,p1 ;③p1(ポート p1) に出力初期データをセット MOV.B #11110000B,pd1 ;④pd1(ポート p1 方向レジスタ) に入出力方向を設定。1:出力,0:入力 MOV.B #00000000B,pd3 ;⑤pd3(ポート p3 方向レジスタ) に入出力方向を設定。1:出力,0:入力 MOV.B #0,R0L ;⑥SW1 を押したカウントを 0 にする Loop: MOV.B R0L,R0H ;⑦カウント値を表示用レジスタ(R0H)にコピー SHL.B #4,R0H ;⑧表示用レジスタ(R0H)を 4bit 左シフト NOT.B R0H ;⑨LED をつけるために反転 MOV.B R0H,p1 ;⑩LED へ出力 SW1_OFF: BTST p3_3 ;⑪SW1 の bit をチェック JC SW1_OFF ;⑫SW1 が OFF の間は⑪⑫を繰り返して待つ ;★⑬~⑮はチャタリング除去のための時間待ち(約 18ms 待つ) MOV.W #30000,R3 (1) ;⑬ループカウンタ←30000(約 18ms 待つためのデータ)[1 サイクル] Chatter1: SUB.W #1,R3 ;⑭チャタリング除去時間待ち(カウンタ減算)[2 サイクル] JNZ Chatter1 ;⑮チャタリング除去時間待ち(ループ終了判定)[4 サイクル/2 サイクル] SW1_ON: BTST p3_3 ;⑯SW1 の bit をチェック JNC SW1_ON ;⑰SW1 が ON の間は⑯⑰を繰り返して待つ ;★⑱~⑳はチャタリング除去のための時間待ち(約 18ms 待つ) MOV.W #30000,R3 (1) ;⑱ ループカウンタ←30000(約 18ms 待つためのデータ)[1 サイクル] Chatter2: SUB.W #1,R3 ;⑲チャタリング除去時間待ち(カウンタ減算)[2 サイクル] JNZ Chatter2 ;⑳チャタリング除去時間待ち(ループ終了判定)[4 サイクル/2 サイクル] ADD.B #1,R0L ;21 SW1 を押したカウントを+1 JMP Loop ;22 最初から繰り返し .END
4-30 解説6 (1)時間待ちプログラム(ここではチャタリング除去に応用) ➢ 各命令の実行時間はマニュアルに示されている「サイクル数」で計算できる。 ➢ 1 サイクルとは,動作クロック 1 周期分をいう。 ➢ 例えば動作クロックが 10MHz であれば,1 サイクル分の実行時間は 0.1μs である。 命令実行に 3 サイクルかかる命令は 0.1μs×3 サイクル=0.3μs の実行時間がかか る。 ➢ 例題 6 のプログラム中の枠内(1)のようにループカウンタの減算だけをするルー プを挿入すると,時間待ちをすることができる。 ➢ この例題の場合,正確に待ち時間ループのサイクル数を求めると 1 サイクル + (2 サイクル + 4 サイクル)×30000 回 – 2 サイクル = 179999 サイクル となるが, 1 サイクル + (2 サイクル + 4 サイクル)×30000 回 – 2 サイクル = 180000 サイクル とみなしてもほとんど問題ない。したがって,動作クロックが 10MHz であれば, この待ち時間ループの所要時間は 0.1μs × 180000 サイクル = 18ms である。
問17 【回路図1】 SW1 を押して離した度に,SW1 を押した回数を LED に表示する。また SW2 を押して離したたびに,表示している SW1 の押した回数を 1 つ減らしなさい。ただし LED1 を LSB,LED4 を MSB とし,2 進数の”1”は点灯,”0”は消灯とする。プログラム動作時は,0000B を LED に表示する。スイッチのチャタリング処理を行うこと。プログラムは永久ループの構造 にする。
問18 【回路図1】 DIP-SW の ON 状態を”0”,OFF 状態を”1”と見立てる。DIP-SW の 1 を LSB,DIP-SW の 4 を MSB としてできる 4bit の 2 進数を考える。プログラムが動作したら,ま ず,0000B を LED に表示する。その後,SW1 を押して離した度に,DIP-SW から入力した 2 進 数を LED の表示に加算しなさい。ただし LED1 を LSB,LED4 を MSB とし,2 進数の”1”は点灯,”0” は消灯とする。スイッチのチャタリング処理を行うこと。プログラムは永久ループの構造にす る。加算をして 4bit より大きくなる場合については考慮しなくて良い。
問19 【回路図1】 DIP-SW の ON 状態を”0”,OFF 状態を”1”と見立てる。DIP-SW の 1 を LSB,DIP-SW の 4 を MSB としてできる 4bit の 2 進数を考える。プログラムが動作したら,ま ず,0000B を LED に表示する。その後,SW1 を押して離したに DIP-SW から入力した 2 進数を LED の表示に加算し,また SW2 を押して離した度に DIP-SW から入力した 2 進数を LED の表示 から減算しなさい。ただし LED1 を LSB,LED4 を MSB とし,2 進数の”1”は点灯,”0”は消灯 とする。スイッチのチャタリング処理を行うこと。プログラムは永久ループの構造にする。加 算や減算をして 4bit より大きくなる場合や小さく場合については考慮しなくて良い。
4-32 例題7 【回路図2】動作開始時に LED をすべて消灯する。その後,LED を LSB から1つずつ 順番に点灯しては消灯して行く動作を MSB まで繰り返す。MSB を点灯/消灯させたら,再び LSB から同様の動作を繰り返し続けなさい。 .ORG 0D000h ;① 次のプログラムを格納する先頭アドレスを 0D000h とする MOV.B #00000000B,p1drr ;② p1drr(ポート p1 駆動能力制御レジスタ) ← すべて Low にする MOV.B #11111111B,p1 ;③ p1(ポート p1) に出力初期データをセット(全部消灯) MOV.B #11111111B,pd1 ;④pd1(ポート p1 方向レジスタ) に入出力方向を設定。1:出力,0:入力 Lsb: MOV.B #11111110B,R0L ;⑤LSB を点灯する初回の点灯データを R0L に用意 Loop: MOV.B R0L,p1 ;⑥点灯データを LED へ出力 MOV.W #500,R2 ;⑦2 重ループの外側ループの時間待ちループカウンタ R2←500[1 サイクル] WaitLoop1: MOV.W #1000,R3 ;⑧2 重ループの内側ループの時間待ちループカウンタ R3←1000[1 サイクル] WaitLoop2: NOP (1) ;⑨何もしない命令で時間稼ぎ[1 サイクル] NOP (1) ;⑩何もしない命令で時間稼ぎ[1 サイクル] NOP (1) ;⑪何もしない命令で時間稼ぎ[1 サイクル] SBJNZ.W #1,R3,WaitLoop2(2);⑫2 重ループの内側ループの終了判定[7 サイクル/3 サイクル] SBJNZ.W #1,R2,WaitLoop1(2);⑬2 重ループの外側ループの終了判定[7 サイクル/3 サイクル] SHL.B #1,R0L ;⑭点灯 LED データを1bit 左へシフト(LSB には 0 が入ってくる) ADD.B #00000001B,R0L ;⑮点灯 LED データの LSB を 1 にする CMP.B #11111111B,R0L(4);⑯点灯データが 11111111B かどうかチェック JNZ Loop ;⑰点灯データが 11111111B でなければ繰り返す JMP Lsb ;⑱点灯データが 11111111B ならば Lsb からやり直す .END 時間待ちA 時間待ちB
解説7 (1)ノーオペレーション NOP オペレーション(動作) 何もしない。1サイクル使用する。 用途 1サイクル分の時間を待ちたいときに使う (2)減算&条件分岐 SBJNZ.B #数値 , 8bit レジスタ, ジャンプ先アドレス(ラベル) SBJNZ.W #数値 , 16bit レジスタ, ジャンプ先アドレス(ラベル) オペレーション(動作) ① 8bit(16bit)レジスタ ← 8bit(16bit)レジスタ - #数値 ② ①の演算後,8bit(16bit)レジスタ≠0 ならばジャンプ先アドレスへジャンプす る (3)加算&条件分岐 ADJNZ.B #数値 , 8bit レジスタ, ジャンプ先アドレス(ラベル) ADJNZ.W #数値 , 16bit レジスタ, ジャンプ先アドレス(ラベル) オペレーション(動作) ① 8bit(16bit)レジスタ ← 8bit(16bit)レジスタ + #数値 ② ①の演算後,8bit(16bit)レジスタ≠0 ならばジャンプ先アドレスへジャンプす る ※ 8bit(16bit)レジスタが,11111111B(1111111111111111B)のときに, +1 を加算すると,8bit(16bit)レジスタは 00000000B(0000000000000000B) -7≦数値≦+8 R0,R1,R2,R3,A0,A1 R0L,R0H,R1L,R1H -8≦数値≦+7 R0,R1,R2,R3,A0,A1 R0L,R0H,R1L,R1H
4-34 (4)比較命令 CMP.B #IMM, 8bit レジスタ CMP.W #IMM, 16bit レジスタ CMP.B 8bit レジスタ , 8bit レジスタ CMP.W 16bit レジスタ, 16bit レジスタ オペレーション(動作) ・ 比較対象②-比較対象①の減算を仮に試算して,減算結果の状態をフラグ レジスタに残す。フラグを見ると大小関係がわかる。あくまで減算は試算 であり,減算結果は捨てられて,実行後の比較対象②の値は実行前と同じ である。 ・ C フラグの変化 大小関係 比較対象②-比較対象① C フラグ 比較対象② > 比較対象① 比較対象②-比較対象① > 0 C = 1 比較対象② = 比較対象① 比較対象②-比較対象① = 0 C = 1 比較対象② < 比較対象① 比較対象②-比較対象① < 0 C = 0 ・ Z フラグの変化 大小関係 比較対象②-比較対象① Z フラグ 比較対象② > 比較対象① 比較対象②-比較対象① > 0 Z = 0 比較対象② = 比較対象① 比較対象②-比較対象① = 0 Z = 1 比較対象② < 比較対象① 比較対象②-比較対象① < 0 Z = 0 ・ S フラグおよび O フラグも変化をするが,授業では説明を省略する。 ・ この比較命令は,条件分岐(JC,JNC,JZ,JNZ)の直前に用い,比較結果を フラグに残す。そして比較命令の次に書かれた条件分岐は,そのフラグの 値をジャンプするかしないかの条件として利用する。 比較対象② 比較対象①
例 1)CMP.B R0L, R1L R1L-R0L を試算。演算結果残らず。フラグが変化。 ➢ R1L>R0L ならば C=1,Z=0 となる ➢ R1L=R0L ならば C=1,Z=1 となる ➢ R1L<R0L ならば C=0,Z=0 となる もし CMP.B R0L, R1L JNZ Start : : というプログラムを実行すると, R1L=R0L の時・・・そのまま下のプログラムへ R1L≠R0L の時・・・Start へジャンプ となる。
4-36 問20 例題7の時間待ち A と時間待ち B は,それぞれ何秒の時間待ちができるか。CPU の動 作クロックは 10MHz とする。 問21 【回路図2】動作開始時に LED をすべて消灯する。その後,LED を MSB から1つずつ 順番に点灯しては消灯して行く動作を LSB まで繰り返す。LSB を点灯/消灯させたら,再び MSB から同様の動作を繰り返し続けなさい。LED の点灯間隔時間は例題7と同じでよい。 問22 【回路図2】動作開始時に LED をすべて消灯する。その後,LED を MSB から1つずつ 順番に点灯しては消灯して行く動作を LSB まで繰り返す。LSB を点灯/消灯させたら,今度は, LSB から逆方向に1つずつ順番に点灯しては消灯して行く動作を MSB まで繰り返す。この一連 の動作が終わったら,同様の動作を繰り返し続けなさい。LED の点灯間隔時間は約 0.2 秒にし てみよ。CPU の動作クロックは 10MHz とする。 問23 【回路図2】LED を(MSB)○●○●○●○●(LSB)と(MSB)●○●○●○●○(LSB) のパターンを交互に点灯させ続けなさい。点灯間隔時間は約 0.3 秒とする。CPU の動作クロッ クは 10MHz とする。動作開始時には LED を(MSB)○●○●○●○●(LSB)とする。 回路図 2 p3_3 p3_4 (LSB) p1_0 p1_7 (MSB)
例題8 【回路図2】「LED1 を 0.5 秒間点灯と 1 秒間消灯」を交互に繰り返す。なお,電源が 入った直後の初期設定では LED は全て消灯する。 .ORG 0D000h ;①次のプログラムを格納する先頭アドレスを 0D000h とする LDC #0500H,isp ;②LDC 命令は例題 9 で説明をする。サブルーチン利用時には必須 MOV.B #00000000B,p1drr ;③ p1drr(ポート p1 駆動能力制御レジスタ) ← すべて Low にする MOV.B #11111111B,p1 ;④ p1(ポート p1) に出力初期データをセット MOV.B #11111111B,pd1 ;⑤ pd1(ポート p1 方向レジスタ) に入出力方向設定。1:出力,0:入力 MOV.B #00000000B,pd3 ;⑥ pd3(ポート p3 方向レジスタ) に入出力方向設定。1:出力,0:入力 LED_ON: BCLR p1_0(1) ;⑦ LED1 を点灯 JSR Wait05s (3) ;⑧ 0.5 秒待ちサブルーチンコール BSET p1_0(2) ;⑨ LED1 を消灯 JSR Wait05s ;⑩ 0.5 秒待ちサブルーチンコール JSR Wait05s ;⑪ 0.5 秒待ちサブルーチンコール JMP LED_ON ;⑫ 永久ループ ;***** ここより 0.5 秒待ちのサブルーチン(例題 7 の時間待ちと同じ) Wait05s: ; ⑬サブルーチンの先頭につけたラベルがサブルーチン名になる MOV.W #500,R2 ;⑭2 重ループの外側ループの時間待ちループカウンタ R2←500[1 サイクル] WaitLoop1: MOV.W #1000,R3 ;⑮2 重ループの内側ループの時間待ちループカウンタ R3←1000[1 サイクル] WaitLoop2: NOP ;⑯何もしない命令で時間稼ぎ[1 サイクル] NOP ;⑰何もしない命令で時間稼ぎ[1 サイクル] NOP ;⑱何もしない命令で時間稼ぎ[1 サイクル] SBJNZ.W #1,R3,WaitLoop2 ;⑲2 重ループの内側ループの終了判定[7 サイクル/3 サイクル] SBJNZ.W #1,R2,WaitLoop1 ;⑳2 重ループの外側ループの終了判定[7 サイクル/3 サイクル] RTS (4) ;21サブルーチンを終了し呼び出した命令の次の命令に実行を移す .END サブルーチンの先頭に付けたラベルが,サブル ーチンを呼び出すときに「JSR Wait05s」の ように使用される。 サブルーチンの終わりは必ず「RTS」命令で終 える
4-38 解説8 (1)指定した bit を“0”にクリアする (ビットクリア命令) BCLR bit シンボル オペレーション(動作) bit シンボルの示す bit のみを“0”にする。 (2)指定した bit を“1”にセットする (ビットセット命令) BSET bit シンボル オペレーション(動作) bit シンボルの示す bit のみを“1”にする。 (3)(4)サブルーチンコール(呼び出し)とリターン JSR 命令(Jump Subroutine ) JSR 命令で指定されたラベルのサブルーチンに実行を移す。 JSR サブルーチン先頭アドレス(ラベル) 動作:①戻りアドレス(呼び出した JSR 命令の次の命令があるアドレス)を スタックに記憶 スタックについては例題 9 で説明する ②サブルーチン先頭アドレスに実行を移す RTS 命令(Retern from Subroutine )
サブルーチンを終えて,コールした JSR 命令の次の命令に実行を戻す。 RTS 動作:①スタックに記憶していた戻りアドレスを取り出して PC に入れること によって,呼び出した JSR 命令の次の命令に実行を戻す。 例えばチャタリング待ちをサブルーチン化すると下図のようになる p1_7,p1_6,p1_5,p1_4,p1_3,p1_2,p1_1,p1_0 などの bit シンボル p1_7,p1_6,p1_5,p1_4,p1_3,p1_2,p1_1,p1_0 などの bit シンボル <メインプログラム> : : JSR ChatterWait : : : : JSR ChatterWait : : <サブルーチン> ChatterWait: MOV.W #30000,R3 Chatter1: SUB.W #1,R3 JNZ Chatter1 RTS もどる もどる サブルーチンへ サブルーチンへ
問24【回路図2】「LED1 を 1 秒間点灯して消灯し,その後 LED2 を 2 秒間点灯して消灯し, さらに LED3 を 3 秒間点灯して消灯」を繰り返す。なお,電源が入った直後の初期設定では LED は全て消灯する。点灯・消灯は BCLR 命令,BSET 命令を使用する。時間待ちサブルーチンは 1 秒待ちサブルーチン「Wait1s」を作る。2 秒待ちは「Wait1s」を 2 回,3 秒待ちは「Wait1s」 を 3 回呼び出せばよい 問25 【回路図2】図に示した T 字路交差点の自動車専用の交通信号機を作る。道路 B には 感応センサーが設置されているが,道路 A には設置されていない。通常状態において,道路 A の信号機は青,道路 B の信号機は赤になっている。道路 B の感応センサーが車を感知したとき のみ,道路 A の信号機が青から黄(2 秒間維持)を経て赤(10 秒間維持)に変わる。道路 B の 信号機は,道路 A の信号機が赤になったときに,赤から青(8 秒間維持)に変わり,さらに黄 (2 秒間維持)を経て赤に戻る。道路 B の信号機が赤に戻ったとき,道路 A の信号機が青に戻 り,通常状態に戻る。時間待ちサブルーチンは 2 秒待ちサブルーチン「Wait2s」を作る。8 秒 待ちは「Wait2s」を 4 回呼び出せばよい LED1~3 を道路 Bの信号機,LED4~6 を道路 Aの信号機,SW1 を感応センサーに見立ててプ ログラムを作れ。 自動車用の信号機の点灯は MOV 命令を使用する。 道路 A【LED6(p1_5):赤,LED5(p1_4):黄,LED4(p1_3):青】 道路 B【LED3(p1_2):赤,LED2(p1_1):黄,LED1(p1_0):青】 問26 【回路図2】問 25 の信号機に,道路 A を横断するための歩行者用信号機を増設する。 この歩行者用信号機が赤になるのは,信号 A が青および黄のときである。歩行者用信号機が青 になるのは,信号 A が赤になったときである。また,道路 A が赤になって 8 秒後に,歩行者用 信号機は青点滅(0.2 秒間隔)を 2 秒間継続する。その後,歩行者用信号機は赤に戻る。この プログラムを問 25 のプログラムに追加しなさい。歩行者信号は LED7 を青,LED8 を赤とする。 自動車用の信号機の点灯は MOV 命令を使用する。歩行者用の消灯には BSET 命令を使用する。 時間待ちサブルーチンは 2 秒待ちサブルーチン「Wait2s」と 0.2 秒待ちサブルーチン「Wait02s」 を作る。8 秒待ちは「Wait2s」を 4 回呼び出せばよい 道路 A【LED6(p1_5):赤,LED5(p1_4):黄,LED4(p1_3):青】 道路 B【LED3(p1_2):赤,LED2(p1_1):黄,LED1(p1_0):青】 歩行者用【LED8(p1_7):赤,LED7(p1_6):青】 道路B 道路A 感応センサ 道路B 道路A 感応センサ
4-40 問25 の状態遷移図 問26 の状態遷移図 信号機 A:青 信号機 B:赤 信号機 A:赤 信号機 B:青 信号機 A:黄 信号機 B:赤 信号機 A:赤 信号機 B:黄 電源 ON 感応センサ SW1:ON 通常状態 状態1 状態 2 2 秒後 状態 3 状態 4 8 秒後 2 秒後 信号機 A:青 信号機 B:赤 歩行者用:赤 信号機 A:赤 信号機 B:青 歩行者用:青 信号機 A:黄 信号機 B:赤 歩行者用:赤 電源 ON 感応センサ SW1:ON 通常状態 状態1 状態 2 2 秒後 状態 3 状態 4 8 秒後 点滅カウンタ=0 点滅カウ ンタ←5 信号機 A:赤 信号機 B:黄 歩行者用:青 信号機 A:赤 信号機 B:黄 歩行者用:消 点滅カウ ンタ-1 すぐに 0.2 秒後 0.2 秒後 点滅カウンタ≠0 状態 5
例題9 例題7の時間待ちをサブルーチン化したプログラムに変更せよ(サブルーチンのネス ティング(入れ子)を用いた待ち時間処理) .ORG 0D000h ;① 次のプログラムを格納する先頭アドレスを 0D000h とする LDC #0500H,isp ;②スタックポインタ isp に 0500H を設定 Start: MOV.B #00000000B,p1drr ;③drr(ポート p1 駆動能力制御レジスタ) ← すべて Low にする MOV.B #11111111B,p1 ;④p1(ポート p1) に出力初期データをセット MOV.B #11111111B,pd1 ;⑤pd1(ポート p1 方向レジスタ) に入出力方向を設定。1:出力,0:入力 LSB: MOV.B #11111110B,R0L ;⑥LSB を点灯する点灯データの用意 Loop: MOV.B R0L,p1 ;⑦点灯データを LED へ出力 JSR Wait500ms ;⑧0.5s時間待ちサブルーチンコール SHL.B #1,R0L ;⑨点灯 LED データを1つ左へずらす(LSB に 0 が入る) ADD.B #00000001B,R0L ;⑩点灯 LED データの LSB を 1 にする CMP.B #11111111B,R0L ;⑪点灯データが 11111111B かどうかチェック JNZ Loop ;⑫点灯データが 11111111B でなければ繰り返す JMP LSB ;⑬点灯データが 11111111B ならば LSB からやり直す ;***** ここからサブルーチン「Wait500ms」 ***** Wait500ms: MOV.W #500,R2 ;⑭0.5s 時間待ちループカウンタ R2←500[1 サイクル] WaitLoop1: JSR Wait1ms ;⑮1ms 時間待ちサブルーチンコール[8 サイクル] SBJNZ.W #1,R2,WaitLoop1 ;⑯ 0.5s 時間待ちループ終了判定[7 サイクル/3 サイクル] RTS ;⑰リターン[6 サイクル] ;***** ここからサブルーチン「Wait1ms」 ***** Wait1ms: MOV.W #1000,R3 ;⑱1ms時間待ちループカウンタ R3←1000[1 サイクル] WaitLoop2: NOP ;⑲何もしない命令で時間稼ぎ[1 サイクル] NOP ;⑳何もしない命令で時間稼ぎ[1 サイクル] NOP ;21何もしない命令で時間稼ぎ[1 サイクル] SBJNZ.W #1,R3,WaitLoop2 ; 22 1ms時間待ちループの終了判定[7 サイクル/3 サイクル] RTS ;23 リターン[6 サイクル] .END
4-42 解説9 (1)サブルーチンのネスティング(入れ子) この例題はサブルーチンの中から,さらに他のサブルーチンを呼び出している。このようなプ ログラムの構造を「ネスティング」とか,「入れ子」と呼ぶ (2)サブルーチンの呼び出しとリターンのしくみ サブルーチンを JSR 命令で呼び出した後,サブルーチンを RTS 命令で終了すると,必ず呼び出 した側のプログラムの JSR 命令の次の命令に実行が戻ってくる。これは,JSR 命令で呼び出す 際に,その JSR 命令の次の命令があるメモリアドレスを戻りアドレスとして,メモリ内の「ス タック」と呼ばれる記憶領域に保存しておき,RTS 命令でサブルーチンから戻る際にスタック から戻りアドレスを取り出して,そこに実行を写すしくみによって実現している。 【再掲】 ➢ JSR 命令(Jump Subroutine ) JSR 命令で指定されたサブルーチンに実行を移す。 JSR サブルーチン先頭アドレス(ラベル) 動作:①戻りアドレス(呼び出した JSR 命令の次の命令があるアドレス)を スタックに記憶 ②サブルーチン先頭アドレスに実行を移す ➢ RTS 命令(Retern from Subroutine )
サブルーチンを終えて,コールした JSR 命令の次の命令に実行を戻す。 RTS 動作:①スタックに記憶していた戻りアドレスを取り出して PC に入れること によって,呼び出した JSR 命令の次の命令に実行を戻す。 <サブルーチン「Wait1ms」> Wait1ms: MOV.W #1000,R3 : : RTS <メインプログラム> : : JSR Wait500ms : : : : <サブルーチン「Wait500ms」> Wait500ms: MOV.W #500,R2 JSR Wait1ms SBJNZ.W #1,R2,WaitLoop1 RTS もどる もどる サブルーチンへ サブルーチンへ
スタック(Stack)・・・メモリの中で、スタック方式と呼ばれるやり方でデータを記憶する領 域。スタック領域ともいう。スタックへのデータの書き込み・読み出しは、 最後に記憶したデータを最初に取り出す LIFO(Last In, First Out)構造 になっている。逆の見方をすると,最初に記憶したデータを最後に取り出す FILO(First In, Last Out)構造になっている。これはコインホルダや座 布団積みを想像するとわかりやすい。 スタックはメモリのある領域を使用するのだが,スタックを使用する場 合はあらかじめプログラムによってスタック領域の先頭アドレスを指定して おく必要がある。スタックの先頭アドレスはレジスタのひとつであるスタッ クポインタ ISP に記憶する。スタックポインタには,スタックの先頭アドレ ス(記憶順が最後となっているデータのアドレス)が常に記憶されている。 スタックからデータが取り出されたり,スタックにデータが記憶(データを 積む)したりすると,マイコンが自動的にスタックポンタを変更し,常にス タックポインタがスタックの先頭アドレス(記憶順が最後となっているデー タのアドレス)を指し示すようになっている。 R8C のスタックポインタには ISP と USP と呼ばれるものがあるが,授業で は ISP を使用する。スタックを使用する場合(サブルーチンコールや割込み 処理などの利用時)は,プログラムの先頭においてスタックポインタ ISP へ の初期アドレス値を,LDC 命令を使って設定しておく。この設定をしないと, スタックポインタが適当な値となっておりマイコンが暴走をする可能性が ある。 スタックはデータを記憶するときはアドレスが小さい方向に記憶させて いく。また、データを取り出すときはアドレスが大きい方向へ向かって取り 出しをしていく。 スタック プログラム メモリ 00000h アドレス ISP FFFFFh
4-44 (3)スタックポインタの設定方法 LDC #アドレス値,ISP 動作 スタックポインタ ISP にアドレス値を格納する。 (スタックポインタについては上記のスタックの説明を参照) 授業ではスタックの初期アドレス値は RAM がある 0500H 番地とする。(この値 ならば,プログラムが入るメモリ領域と重ならない)
(4)スタックの利用のイメージ ①LDC 命令でスタック領域の先頭アドレスを設定(プログラムの先頭で必ず行う) ②スタックへのデータの記憶ととり出しのイメージ 4FBh 4FCh 4FDh 4FEh 4FFh 500h 4FBh 4FCh 4FDh 4FEh 4FFh 500h 4FBh 4FCh 4FDh 4FEh 4FFh 1 番目のデータ 500h 4FBh 4FCh 4FDh 4FEh 2 番目のデータ 4FFh 1 番目のデータ 500h 4FBh 4FCh 4FDh 3 番目のデータ 4FEh 2 番目のデータ 4FFh 1 番目のデータ 500h … 0500h ISP … … … ISP 0500h … … ISP 04FFh … … ISP 04FEh … … ISP 04FDh 1Byte を記憶 ①ISP←ISP-1 ②ISP の指すメモリに 1Byte 記憶 1Byte をとり出す ①ISP の指すメモリから 1Byte とり出し ②ISP←ISP+1 1Byte を記憶 ①ISP←ISP-1 ②ISP の指すメモリに 1Byte 記憶 1Byte を記憶 ①ISP←ISP-1 ②ISP の指すメモリに 1Byte 記憶 1Byte をとり出す ①ISP の指すメモリから 1Byte とり出し ②ISP←ISP+1 1Byte をとり出す ①ISP の指すメモリから 1Byte とり出し ②ISP←ISP+1 初期状態 LDC #0500h,ISP スタック領域は空 スタック領域 スタック領域 スタック領域
4-46
例題 9 の補足(サブルーチン呼び出しにおける復帰先のスタックにおける記憶と取り出し)
問27 【回路図2】LED を(MSB)○●○●○●○●(LSB)と(MSB)●○●○●○●○(LSB) のパターンを交互に点灯させ続けなさい。時間待ちにはサブルーチンを使用し,点灯間隔時間 は約 0.3 秒とする。CPU の動作クロックは 10MHz とする。動作開始時には LED を(MSB)○● ○●○●○●(LSB)とする。(問 23 の時間待ちのサブルーチン化)
問28 【回路図1】DIP-SW の ON 状態を”0”,OFF 状態を”1”と見立てる。DIP-SW の 1 を LSB, DIP-SW の 4 を MSB としてできる 4bit の 2 進数を考える。プログラムが動作したら,まず, 0000B を LED に表示する。その後,SW1 が押される度に DIP-SW から入力した 2 進数を LED の 表示に加算し,また SW2 が押される度に DIP-SW から入力した 2 進数を LED の表示から減算し なさい。ただし LED1 を LSB,LED4 を MSB とし,2 進数の”1”は点灯,”0”は消灯とする。サ ブルーチンを用いてチャタリングを除去すること。CPU の動作クロックは 10MHz とする。(問 19 のチャタリングを除去のサブルーチン化) 問29 【回路図2】LED を ①(MSB)●●●○○●●●(LSB) ②(MSB)●●○●●○●●(LSB) ③(MSB)●○●●●●○●(LSB) ④(MSB)○●●●●●●○(LSB) ⑤(MSB)●○●●●●○●(LSB) ⑥(MSB)●●○●●○●●(LSB) ⑦(MSB)●●●○○●●●(LSB) のパターンで,①~⑦の順番で点灯させ,⑦の点灯が終わったら再び①から同じように点灯を 繰り返す。各パターンの切り替えは 0.2 秒おきとする。CPU の動作クロックは 10MHz とする。
4-48 例題10 1byte データのメモリ操作【数値をメモリに転送】【メモリをレジスタに転送】【レ ジスタをメモリに転送】【メモリ領域の確保】 まず,プログラム命令により内部 RAM の 0400h 番地に数値 123 を,また 0401h 番地に数値 5 を入れておく。その後でこの 0400h 番地と 0401h 番地に入れた 1Byte データを加算して,結 果を 0402h 番地に入れなさい .ORG 0D000h ;① 次のプログラムを格納する先頭アドレスを 0D000h とする
MOV.B #123,Memory1(1);② Memory1 番地(0400h 番地)← 数値 123
MOV.B #5,Memory2(1) ;③ Memory2 番地(0401h 番地)← 数値 5
MOV.B Memory1,R0L(2) ;④ R0L ← Memory1 番地(0400h 番地)の値
MOV.B Memory2,R1L(2) ;⑤ R1L ← Memory2 番地(0401h 番地)の値
ADD.B R1L,R0L ;⑥ R0L ← R0L + R1L
MOV.B R0L,Memory3(3) ;⑦ Memory3 番地(0402h 番地) ← R0L の値
Stop: JMP Stop ;⑧ 実行停止
.SECTION WORK,DATA ;⑨ 擬似命令 内部 RAM 領域を WORK として使用する
.ORG 0400h ;⑩ 擬似命令 ここからのプログラムを 0400h に格納する
Memory1: .BLKB 1 ;⑪ ここのメモリ 1Byte を確保する。アドレスは Memory1
Memory2: .BLKB 1 ;⑫ ここのメモリ 1Byte を確保する。アドレスは Memory2
Memory3: .BLKB 1 ;⑬ ここのメモリ 1Byte を確保する。アドレスは Memory3
.END .BLKB 擬似命令 (メモリ領域の確保) アセンブル時(機械語生成時)にメモリ領域を確保する擬似命令。.BLKB 擬似命令は そのアドレスのメモリから 1Byte 分のメモリ領域をオペランドに指定した個数分をア センブル時(機械語生成時)確保する。オペランドの数値は確保するメモリ領域の個数 を指定する。
例 Memory1: .BLKB 1 ・・・1Byte 領域を 1 個確保(Memory1 番地に 1Byte 分) Memory1: .BLKB 5 ・・・1Byte 領域を 5 個確保(Memory1 番地から 5Byte 分)