組込みシステムにおいてプログラムの速度と
メモリサイズが重要である場合。
.data
msg: .asciiz "Hello World"
.text
.globl main
main: li $v0, 4 # v0レジスタに4をセット syscall(print_str) la $a0, msg # a0レジスタにメッセージのアドレスを格納
syscall # 文字列を出力 jr $ra # リターン
Hello World のソースプログラム
疑似命令 .data データ領域の開始 疑似命令 .asciiz "Strings": 文字列を配置 ラベル
疑似命令 globl L ラベル L を大局的に参照可能な記号と宣言する
疑似命令 .text テキスト領域の開始
MIPS の練習
アセンブラのソース
Text領域
(命令コード)
データ領域
(命令コード)
実行結果 QtSpimの出力
.data
msg: .asciiz "Hello World"
.text
.globl main
main: li $v0, 4 # syscall 4 (print_str) la $a0, msg # argument: string syscall # print the string jr $ra # retrun to caller
スタートアップ
アセンブラ言語の形
mainの処理
#Text領域
#Data領域 .text
.globl main main:
jr $ra
.data _start:
jal main スタートアップルーチン、自動的に生成される
テキスト領域(プログラム領域)
データ領域
グローバル変数
疑似命令
セグメント、ラベル、データの宣言
.text: テキスト領域の開始
例 .text[addr]
.data: データ領域の開始
例
.globl L: ラベル L を大局的に参照可能な記号と宣言する。
例 .globl main
.word n: 1 語のデータ n を配置。
.space n: n バイトの領域を確保
.asciiz "Strings": 文字列を配置。 ( 末尾に NULL 文字を追加 )
足し算の例
add.asm
# Text Segment
.text
.globl main main:
addi $a0,$zero,5 # a0=5 addi $a1,$zero,10 # a1=10 add $v0,$a0,$a1 # v0=a0+a1
jr $ra #main の終了
#Data Segment
.data
マクロ命令
レジスタの初期化
Li (Load Immediate) 命令
La (Load Address) 命令
la rs, addr 意味 rs <=addr (32bit)
move(Move) 命令
move rd, rs 意味 rd <=rs
実際の命令
li Rd, value
lui $at, Upper 16-bits of value ori Rd, $at, Lower 16-bits of value
la Rd, Label
lui $at, Upper 16-bits of Label ori Rd, $at, Lower 16-bits of Label
move Rd, Rs addu Rd, $0, Rs
実際の機械語では
16bitの即値しか扱えないので
2回に分ける
実際の機械語では
16bitの即値しか扱えないので
2回に分ける
自分のPCに QPSIM をインストールして実行できるようにしておくこと
MIPSのプログラミングについては下記URLが 参考になる。 その他日本語サイトも
アセンブラプログラムの開始
スタートアップ lw $a0 0($sp) addiu $a1 $sp 4 addiu $a2 $a1 4 sll $v0 $a0 2
addu $a2 #a2 $vo jal main
アセンブラプログラムの開始
lw $a0 0($sp)
addiu $a1 $sp 4 addiu $a2 $a1 4 sll $v0 $a0 2
addu $a2 #a2 $vo jal main
C 言語のmain関数の引数
main(argc, argv)
$4 arggc
$5 argv
$6 環境変数のポインタ
# シャープはコメントを表す. # このプログラムはa=b+cを実行する.
# a=$s0, b=$s1, c=$s2とする
# addi命令は第2オペランドに定数が書ける
# $zeroは常に値が0のレジスタ
# 最初に実行する関数はmainと決まっているのでmainを宣言する必要がある.
# .globl main
# main関数の宣言. main: addi $s1, $zero, 1
# b=$s1=1 addi $s2, $zero, 2
# c=$s2=2 add $s0, $s1, $s2
# a=$s0=b+c=3 jr $ra
# プログラムの終了
# a=$s0=3になっていることをSPIMシミュレータで確認すること
C のプログラムとアセンブラの比較 例題1
.globl main # main関数の宣言 main: addi $s1, $zero, 1 # b=$s1=1 addi $s2, $zero, 2 # c=$s2=2 add $s0, $s1, $s2 # a=$s0=b+c=3 jr $ra # end
C のプログラムとアセンブラの比較 例題1
C のプログラムとアセンブラの比較 例題 2
main() {int a, b, c;
b=-1;
c=2;
a=b+c;
}
.globl main # a=$s0, b=$s1, c=$s2
main: sub $s1, $zero, 1 # b=$s1=-1 add $s2, $zero, 2 # c=$s2=2
add $s0,$s1,$s2 # a=$s0=b+c=1
jr $ra #
.globl main # a=$s0, b=$s1, c=$s2 main: sub $s1, $zero, 1 # b=$s1=-1 add $s2, $zero, 2 # c=$s2=2 add $s0,$s1,$s2 # a=$s0=b+c=1 jr $ra #
C のプログラムとアセンブラの比較 例題 2
アセンブラプログラムの開始
lw $a0 0($sp)
addiu $a1 $sp 4 addiu $a2 $a1 4 sll $v0 $a0 2
addu $a2 #a2 $vo jal main
C 言語のmain関数の引数
main(argc, argv)
$4 arggc
$5 argv
$6 環境変数のポインタ
main(){
int a, b, c;
b=1;
c=2;
a=b+c;
printf("a=%d¥n) }
C のプログラムとアセンブラの比較 例題 4
# b=1, c=2 とし,a=b+cを計算する.
# その答えを a = 3 とプリントする.
# Data記述部でプリントする文字列を定義しておく.
# Data記述部
.data
str: .asciiz "a = "
.text # mainプログラムをテキストセグメントに置く.
.globl main # mainの宣言. a=$s0, b=$s1, c=$s2とする main: addi $s1, $zero, 1 # b=$s1=1
addi $s2, $zero, 2 # c=$s2=2 add $s0, $s1, $s2 # a=$s0=b+c
# プリントするためのプログラム
addi $v0, $zero, 4 # syscallに文字のprintを指示
la $a0, str # $a0に文字列str:のアドレスを入れる syscall # 文字列"a = "をプリント
add $a0, $s0, $zero # $a0=$s0
addi $v0, $zero, 1 # syscallに整数のprintを指示 syscall # aの値をプリント
jr $ra # プログラムの終了
C のプログラムとアセンブラの比較 例題 4
.data
str: .asciiz "a = "
.text
.globl main main: addi $s1, $zero, 1 addi $s2, $zero, 2 add $s0, $s1, $s2
# プリントするためのプログラム addi $v0, $zero, 4 la $a0, str syscall add $a0, $s0, $zero addi $v0, $zero, 1 syscall jr $ra
C のプログラムとアセンブラの比較 例題 4
Data segment の先頭アドレスが0x10010000, 0x1001=4097
la $a0, str lui $4, 4097[str]
1 0 0 1
$4レジスタ すなわち a0レジスタ 10進の4097は16進で1001 0 0 0 0
上位16bitに
16進の1001を格納
下位16bitは 0を入れる
マクロ命令の使われ方
C のプログラムとアセンブラの比較 例題 5
int x[2];
main() {
Int c;
x[0]=0;
x[1]=6;
c=5;
x[0]=x[1]+c}
.data
X: .word 0,6
# テキストセグメントを定義する.
.text
.globl main # main関数の宣言.
main:
la $s1, X # $s1に配列x[0]のアドレス
addi $s3, 5 # c=$s3=5
lw $s6, 4($s1) # $s6=x[1] $6にx[1]をロード
# PCSpimでメニューのsimulator→settingsでdelayed loadにチェックを入れると,
# lw命令は値をレジスタにロードするのに2サイクルかかるようになる.
# チェックをはずすとlw命令を1サイクルで実行する.
# ここではメモリが遅いためロードは2サイクルかかるとする.
# lwの1サイクル後はレジスタにまだloadする値が入っていない.そこで意味のない
# 命令を実行してもう1サイクル時間を遅らせる.
add $t1, $t1, $zero # load delayのため1サイクル遅らせる
意味のない命令