as-5. サブルーチン呼び出しの
メカニズム
1
金子邦彦
68000 アセンブラプログラミング)
URL: https://www.kkaneko.jp/cc/as/index.html
種々のオペランド
move.w #200,%d2
/* #200 10進数. d2 の上位バイトは変化しない */
move.l #0x01,%d1
/* #0x01 16進数. d0 0x00000000 がセットされる */
.equ BUFFER_SIZE 100
move.w #BUFFER_SIZE,%d2
move.w #0x2700,%sr
/* 割り込み禁 */
move.l %d0,%d1
move.l %d0,(%a0)
/* アドレスレジス a0 がポイントするメモリに転送(a0は変化しない) */
move.b #0x00,(%a0)
/* アドレスレジスタ a0 がポイントするメモリに 0 をセット(.b なので1バイ) */
オペランド
「操作」すべきデータの
対象がかかれている部分
割り込み禁止の
決まり文句
データレジスタ直接
(data register direct)
例:
move.w %D0, %D3
記法 %Dn
12345678
ドレスバス
データバス
制御系
Control Unit
+命令長
レジスタ
Registers
R/W
データレジスタ D3
D0 の下位1ワードが
入る
move.w %D0, %D3 の命令実行
D0
????5678
D3
.w」とあるので,下
位1ワードを使う
アドレスレジスタ直接
(address register direct)
例:
move.l %A6, %A0
記法 %An
FF008800
ドレスバス
データバス
制御系
Control Unit
+命令長
レジスタ
Registers
R/W
アドレスレジスタ A0
A6 が入る
move.l %A6, %A0 の命令実行
A6
FF008800
A0
.l」とあるので,
全てを使う
アブソリュート
(absolute)
例:
.equ ADDR 0xffff00
move.w ADDR,%D0
move.w %D1,ADDR
メモリアドレスの値を指定
アドレスバス
データバス
制御系
Control Unit
+命令長
レジスタ
Registers
R/W
D0 の下位1ワード
に入る
move.w ADDR,%D0 の命令実行
????A000
D0
0xffff00
メモリからの
読み出し
アドレスバス
データバス
制御系
Control Unit
+命令長
レジスタ
Registers
R/W
D1 の下位1ワード
がメモリに書き込まれ
move.w %D1, ADDR の命令実行
????????
D1
0xffff00
メモリへの
書き込み
イミディエート (immediate)
例:
move.w #0x0040, %D0
記法 #data
????????
アドレスバス
データバス
制御系
Control Unit
+命令長
レジスタ
Registers
R/W
データレジスタ D0
0040 が入る
move.w #0x0040, %D0 命令実行では
D0
????0040
0040
イミディエート
.equ ADDR 0x00ffff00
move.w #0x1000,%d0
move.l #ADDR,%a0
値を扱う
アブソリュート
.equ ADDR 0xffff00
move.w ADDR,%d0
メモリの読み出し,書き込み
レジスタ間接
(register indirect)
例:
move.w (%A0), %D0
move.w %D3, (%A1)
記法 (%An)
(%A0) (%A7) は可. (%D0) などは許されない
アドレスバス
データバス
制御系
Control Unit
+命令長
レジスタ
Registers
R/W
D0 の下位1ワード
に入る
move.w (%A0),%D0 の命令実行
????????
D0
????????
A0
メモリからの
読み出し
アドレスバス
データバス
制御系
Control Unit
+命令長
レジスタ
Registers
R/W
D3 の下位1ワード
がメモリに書き込まれ
move.w %D3, (%A1) の命令実行
????????
D3
????????
A1
メモリへの
書き込み
レジスタ直接とレジスタ間接の違い
レジスタ直接
move.l #0,%D0
move.l %D2,%D0
d0 が書き換わる
レジスタ間接
.equ ADDR 0xffff00
move.l #ADDR,%A0
move.w %D0,(%A0)
A0 に入っているメモリアドレス
使って,データの書き込みが行われる
種々のオペランド(その2)
move.w %sr,-(%sp)
/* システムスタックエリアに sr の中身をプッシュ */
move.w (%sp)+,%sr
/* システムスタックエリアか sr 中身をポップ */
move.w #0x0010, 20(%A0)
/* A0 20 足したメモリアドレスに, 0x0010 を書き込む */
move.w ※※,-(%sp)
move.w (%sp)+,※※
システムスタックエリアへの
プッシュとポップの決まり文句
ポストインクリメント・レジスタ間接
例: move.w (%a0)+, %d0
a0 0x00002000 が入っているとしよう
move.w (%a0), %d0 と同様の処理が行われた後
に,自動的に a0 に2が足される. a0 の値は,
0x00002002 になる
.b なら1足される
.w」なら2足され
.l」なら4足される
プリデクリメント・レジスタ間接
例: move.w -(%a0), %d0
a0 0x00002000 が入っているとしよう
最初に,自動的に a0 から2が引かれる. a0 の値
は, 0x00001ffe になる.その後で,「move.w
(%a0), %d0 と同様の処理が行われる
.b なら1引かれる
.w」なら2引かれる
.l」なら4引かれる
ディスプレースメント付きレジスタ間接
例: move.l 0x20(%a0), %d0
a0 0x00002000 が入っているとしよう
0x00002000 0x20 が足されて,メモリアドレス
0x00002020 から,4バイト読み込まれて,d0
入る
数値(%レジスタ名)
例: lea 0x2000, %a0 /* a0 0x2000 をセット*/
move.b 4(%a0), %d0 /* 0x2004 から1バイト読みこみ */
move.w 4(%a0), %d0 /* 0x2004 から2バイト読みこみ */
move.l 4(%a0), %d0 /* 0x2004 から4バイト読みこみ */
構造体
例: 住所録
名前 20バイト
身長 2バイト move.w 20(%a0), %d0
年齢 1バイト move.b 22(%a0), %d0
性別 1バイト move.b 23(%a0), %d0
全体で 24バイトのデータ
20
22
23
68000 のアドレッシングモード
モード 記法
データレジスタ
データレジスタ
%Dn %D0, %D1, %D7
アドレスレジスタ
直接
アドレスレジスタ
%An %A0, %A1, %A7
アブソリュート
メモリアドレス
xx 0x00ffffff00, ADDR
レジスタ間接
括弧付き
(%An)
(%A0), (%A1), (%A7)
ポストインクリメン
ト・レジスタ間接
後ろに+付き
(%An)+
(%A0)+, (%A1)+, (%A7)+
プリデクリメント・
レジスタ間接
前に 付き
-(%An)
-(%A0), -(%A1), -(%A7)
ディスプレースメント
付きレジスタ間接
前に数値付き
d16(%An) 20(%A0),
BOTTOM(%A0)
イミディエート
数値
#data
#3, #0x2000, #ADDR
アドレッシングモード
命令の種類によって,書くことができるアドレッシ
ングモードに制限がある
例: cmp 命令では
cmp.w (%a2)+, %d2 は動く
cmp.w %d2, (%a2)+ 動かない
配布資料「37 CMP」のページを見よ
CMP.{.B/.W/.L} <ea>, Dn
とあるのは,2番目のオペランドにデータレジ
スタしか書けないという意味
C 言語での関数呼び出し
例題1
文字列の長さを数える関数
関数の
本体
関数名
関数の入力(パラメータ)
例題1.関数呼び出し(1)
1つの関数
1つの関数
関数呼び出し
プログラム実行は
メイン関数から始まる
戻り
変数
変数
変数名
データ(数値や文字)を入れるもの
英数字かアンダーバー(_)で作られる
最初の文字には数字は使えない
大文字と小文字を区別する
変数 i
変数 i をメモリエリア中に確保
変数len をメモリエリア中に確保
ここで使用
変数は2種類使っている
2バイトデータ(整数)
を扱う short int
メモリアドレスを扱う
char *
short int が2バイトになる
という決まりは無いが,
2バイトになっていることが
多い
変数は2種類使っている
2バイトデータ(整数)
を扱う short int
メモリアドレスを扱う
char *
short int が2バイトになる
という決まりは無いが,
2バイトになっていることが
多い
関数の入力(パラメータ)
この時点では
str 文字列の先頭
アドレス
char *
s 文字列の先頭
アドレス + 17
char *
len
17
int
実際のメモリの中身
str
s
str 文字列の先頭
アドレス
char *
s 文字列の先頭
アドレス + 17
char *
len
17
int
len
len s があるメモリエリアは,関数 stringlength 実行のために
ダイナミックに確保されたエリア
(参考)実際のメモリの中身
文字列データは,len, s などとは別の
メモリエリアに入っている
関数呼び出し
1. 制御の流れ
2. 関数のパラメータ
3. 関数内のローカル変数
4. 関数からの返り値
68000 アセンブラ言語での
関数呼び出し
.data
str1:
.ascii "My Name is David!¥0"
SYS_STK:
.ds.b 0x4000
SYS_STK_TOP:
.text
stringlength:
link.w %a6,#-8
clr.w -2(%a6)
move.l 8(%a6),-6(%a6)
start1:
move.l -6(%a6),%a0
cmp.b #0,(%a0)
beq break1
addq.l #1,-6(%a6)
addq.w #1,-2(%a6)
bra start1
break1:
move.w -2(%a6),%a0
move.l %a0,%d0
unlk %a6
rts
main:
lea.l SYS_STK_TOP,%a7
lea.l str1,%a0
move.l %a0,-(%a7)
jsr stringlength
addq.l #4,%a7
.dc.w 0x4848
stop #0
.end
C言語
68000アセンブラ言語
等価
.data
str1:
.ascii "My Name is David!¥0"
SYS_STK:
.ds.b 0x4000
SYS_STK_TOP:
.text
stringlength:
link.w %a6,#-8
clr.w -2(%a6)
move.l 8(%a6),-6(%a6)
start1:
move.l -6(%a6),%a0
cmp.b #0,(%a0)
beq break1
addq.l #1,-6(%a6)
addq.w #1,-2(%a6)
bra start1
break1:
move.w -2(%a6),%a0
move.l %a0,%d0
unlk %a6
rts
main:
lea.l SYS_STK_TOP,%a7
lea.l str1,%a0
move.l %a0,-(%a7)
jsr stringlength
addq.l #4,%a7
.dc.w 0x4848
stop #0
.end
C言語
68000アセンブラ言語
関数呼び出し
(文字列の先頭アドレスを関数に渡す)
.data
str1:
.ascii "My Name is David!¥0"
SYS_STK:
.ds.b 0x4000
SYS_STK_TOP:
.text
stringlength:
link.w %a6,#-8
clr.w -2(%a6)
move.l 8(%a6),-6(%a6)
start1:
move.l -6(%a6),%a0
cmp.b #0,(%a0)
beq break1
addq.l #1,-6(%a6)
addq.w #1,-2(%a6)
bra start1
break1:
move.w -2(%a6),%a0
move.l %a0,%d0
unlk %a6
rts
main:
lea.l SYS_STK_TOP,%a7
lea.l str1,%a0
move.l %a0,-(%a7)
jsr stringlength
addq.l #4,%a7
.dc.w 0x4848
stop #0
.end
C言語
68000アセンブラ言語
リターン
.data
str1:
.ascii "My Name is David!¥0"
SYS_STK:
.ds.b 0x4000
SYS_STK_TOP:
.text
stringlength:
link.w %a6,#-8
clr.w -2(%a6)
move.l 8(%a6),-6(%a6)
start1:
move.l -6(%a6),%a0
cmp.b #0,(%a0)
beq break1
addq.l #1,-6(%a6)
addq.w #1,-2(%a6)
bra start1
break1:
move.w -2(%a6),%a0
move.l %a0,%d0
unlk %a6
rts
main:
lea.l SYS_STK_TOP,%a7
lea.l str1,%a0
move.l %a0,-(%a7)
jsr stringlength
addq.l #4,%a7
.dc.w 0x4848
stop #0
.end
C言語
68000アセンブラ言語
関数での処理結果を,
呼び出し側に引き渡す
.data
str1:
.ascii "My Name is David!¥0"
SYS_STK:
.ds.b 0x4000
SYS_STK_TOP:
.text
stringlength:
link.w %a6,#-8
clr.w -2(%a6)
move.l 8(%a6),-6(%a6)
start1:
move.l -6(%a6),%a0
cmp.b #0,(%a0)
beq break1
addq.l #1,-6(%a6)
addq.w #1,-2(%a6)
bra start1
break1:
move.w -2(%a6),%a0
move.l %a0,%d0
unlk %a6
rts
main:
lea.l SYS_STK_TOP,%a7
lea.l str1,%a0
move.l %a0,-(%a7)
jsr stringlength
addq.l #4,%a7
.dc.w 0x4848
stop #0
.end
C言語
68000アセンブラ言語
関数実行のために,メモリ
エリアをダイナミックに確保
(関数実行の終わりで解放)
.data
str1:
.ascii "My Name is David!¥0"
SYS_STK:
.ds.b 0x4000
SYS_STK_TOP:
.text
stringlength:
link.w %a6,#-8
clr.w -2(%a6)
move.l 8(%a6),-6(%a6)
start1:
move.l -6(%a6),%a0
cmp.b #0,(%a0)
beq break1
addq.l #1,-6(%a6)
addq.w #1,-2(%a6)
bra start1
break1:
move.w -2(%a6),%a0
move.l %a0,%d0
unlk %a6
rts
main:
lea.l SYS_STK_TOP,%a7
lea.l str1,%a0
move.l %a0,-(%a7)
jsr stringlength
addq.l #4,%a7
.dc.w 0x4848
stop #0
.end
C言語
68000アセンブラ言語
「スタックエリア」の確保と,
そのメモリアドレスを A7 にセット
.data
str1:
.ascii "My Name is David!¥0"
SYS_STK:
.ds.b 0x4000
SYS_STK_TOP:
.text
stringlength:
link.w %a6,#-8
clr.w -2(%a6)
move.l 8(%a6),-6(%a6)
start1:
move.l -6(%a6),%a0
cmp.b #0,(%a0)
beq break1
addq.l #1,-6(%a6)
addq.w #1,-2(%a6)
bra start1
break1:
move.w -2(%a6),%a0
move.l %a0,%d0
unlk %a6
rts
main:
lea.l SYS_STK_TOP,%a7
lea.l str1,%a0
move.l %a0,-(%a7)
jsr stringlength
addq.l #4,%a7
.dc.w 0x4848
stop #0
.end
C言語
68000アセンブラ言語