ex05_2012.pptx

Similar documents
ex04_2012.ppt

スライド 1

スライド 1

ex03_2012.ppt

スライド 1

Microsoft PowerPoint - 11.pptx

プログラミング入門1

Microsoft PowerPoint - 計算機言語 第7回.ppt

Microsoft PowerPoint ppt

gengo1-11

C プログラミング演習 1( 再 ) 2 講義では C プログラミングの基本を学び 演習では やや実践的なプログラミングを通して学ぶ

RH850の割り込み/例外実現方法 CC-RHアプリケーションガイド

Prog1_10th

Microsoft PowerPoint ppt

関数 C 言語は関数の言語 関数とは 関数の定義 : f(x) = x * x ; 使うときは : y = f(x) 戻り値 引数

(1) プログラムの開始場所はいつでも main( ) メソッドから始まる 順番に実行され add( a,b) が実行される これは メソッドを呼び出す ともいう (2)add( ) メソッドに実行が移る この際 add( ) メソッド呼び出し時の a と b の値がそれぞれ add( ) メソッド

プログラミング実習I

PowerPoint プレゼンテーション

CASL入門

Microsoft PowerPoint - exp2-02_intro.ppt [互換モード]

Microsoft PowerPoint ppt

プログラミング入門1

PowerPoint プレゼンテーション

PowerPoint プレゼンテーション

Microsoft Word - QtSimulator-H28A.docx

Microsoft PowerPoint - prog07.ppt

また RLF 命令は 図 2 示す様に RRF 命令とは逆に 各ビットを一つずつ 左方向に回転 ( ローテイト ) する命令である 8 ビット変数のアドレスを A とし C フラグに 0 を代入してから RLF A,1 を実行すると 変数の内容が 左に 1 ビットシフトし 最下位ビット (LSB)

PowerPoint プレゼンテーション

Microsoft PowerPoint - C言語の復習(配布用).ppt [互換モード]

Prog1_6th

Microsoft PowerPoint - ca ppt [互換モード]

主記憶の使われ方 システム領域 SP スタックポインタ システム用 スタック用 プログラム起動時に OS によって確 保される (SP が決められる ) プログラム用 メインルーチン プログラム領域 命令コードの列定数 変数用領域サブルーチン命令コードの列 先頭番地は リンク時に OS によって決め

Microsoft PowerPoint - kougi7.ppt

PowerPoint プレゼンテーション

memo

Microsoft PowerPoint - 10.ppt [互換モード]

Microsoft Word - no11.docx

Microsoft PowerPoint - kougi9.ppt

/*Source.cpp*/ #include<stdio.h> //printf はここでインクルードして初めて使えるようになる // ここで関数 average を定義 3 つの整数の平均値を返す double 型の関数です double average(int a,int b,int c){

1 はじめに このアプリケーションは 計算機ハードウェア論 のアセンブリ言語 ( 超簡単命令セット ) の理解を助けるために製作されました 便宜的に機能を追加 削除した箇所があるため このアプリケーション上での動き方が実際のCPUでの動き方と異なる場合があることに留意してください このアプリケーショ

Microsoft Word - no202.docx

バイオプログラミング第 1 榊原康文 佐藤健吾 慶應義塾大学理工学部生命情報学科

コマンドラインから受け取った文字列の大文字と小文字を変換するプログラムを作成せよ 入力は 1 バイトの表示文字とし アルファベット文字以外は変換しない 1. #include <stdio.h> 2. #include <ctype.h> /*troupper,islower,isupper,tol

gengo1-10

計算機アーキテクチャ

関数の動作 / printhw(); 7 printf(" n"); printhw(); printf("############ n"); 4 printhw(); 5 関数の作り方 ( 関数名 ) 戻り値 ( 後述 ) void である. 関数名 (

メソッドのまとめ

書式に示すように表示したい文字列をダブルクォーテーション (") の間に書けば良い ダブルクォーテーションで囲まれた文字列は 文字列リテラル と呼ばれる プログラム中では以下のように用いる プログラム例 1 printf(" 情報処理基礎 "); printf("c 言語の練習 "); printf

情報処理Ⅰ演習

第1回 プログラミング演習3 センサーアプリケーション

Microsoft PowerPoint - CproNt02.ppt [互換モード]

第2回

<4D F736F F D20438CBE8CEA8D758DC F0939A82C282AB2E646F63>

Prog1_6th

ex01_2012.ppt

ソフトウェア基礎技術研修

関数の呼び出し ( 選択ソート ) 選択ソートのプログラム (findminvalue, findandreplace ができているとする ) #include <stdiu.h> #define InFile "data.txt" #define OutFile "surted.txt" #def

memo

始めに, 最下位共通先祖を求めるための関数 LcaDFS( int v ) の処理を記述する. この関数は値を返さない再帰的な void 関数で, 点 v を根とする木 T の部分木を深さ優先探索する. 整数の引数 v は, 木 T の点を示す点番号で, 配列 NodeSpace[ ] へのカーソル

Cコンパイラパッケージお知らせ

プログラミング及び演習 第1回 講義概容・実行制御

プログラミング基礎I(再)

目次

MMUなしプロセッサ用Linuxの共有ライブラリ機構

命令セットの構成例 a) 算術 演算命令 例 )ADD dest, source : dest dest + source SUB dest, source : dest dest - source AND dest, source : dest dest AND source SHR reg, c

PowerPoint Presentation

Microsoft PowerPoint - kougi4.ppt

ブート領域、フラッシュ領域の分割方法 RL78ファミリ用Cコンパイラ CC-RL

講習No.1

char int float double の変数型はそれぞれ 文字あるいは小さな整数 整数 実数 より精度の高い ( 数値のより大きい より小さい ) 実数 を扱う時に用いる 備考 : 基本型の説明に示した 浮動小数点 とは数値を指数表現で表す方法である 例えば は指数表現で 3 書く

プログラミング基礎

Microsoft Word - VBA基礎(6).docx

COMET II のプログラミング ここでは機械語レベルプログラミングを学びます 1

Microsoft PowerPoint - 09.pptx

SuperH RISC engine C/C++ コンパイラ Ver.7 不具合内容 - 過去のお知らせ SuperH RISC engine C/C++ コンパイラ Ver.7 台における不具合内容を以下に示します のチェックツールをルネサスエレクトロニクス株式会社のホームページ

スライド 1

program7app.ppt

Microsoft Word - no103.docx

memo

数はファイル内のどの関数からでも参照できるので便利ではありますが 変数の衝突が起こったり ファイル内のどこで値が書き換えられたかわかりづらくなったりなどの欠点があります 複数の関数で変数を共有する時は出来るだけ引数を使うようにし グローバル変数は プログラムの全体の状態を表すものなど最低限のものに留

講習No.10

PowerPoint プレゼンテーション

/* do-while */ #include <stdio.h> #include <math.h> int main(void) double val1, val2, arith_mean, geo_mean; printf( \n ); do printf( ); scanf( %lf, &v

PowerPoint Presentation

コンピュータ工学講義プリント (7 月 17 日 ) 今回の講義では フローチャートについて学ぶ フローチャートとはフローチャートは コンピュータプログラムの処理の流れを視覚的に表し 処理の全体像を把握しやすくするために書く図である 日本語では流れ図という 図 1 は ユーザーに 0 以上の整数 n

関数の呼び出し ( 選択ソート ) 選択ソートのプログラム (findminvalue, findandreplace ができているとする ) #include <stdio.h> #define InFile "data.txt" #define OutFile "sorted.txt" #def

プログラミング実習I

Microsoft Word - 03

C#の基本2 ~プログラムの制御構造~

slide5.pptx

< F2D837C E95CF CF68A4A94C5816A2E6A>

PowerPoint Presentation

ポインタ変数

Microsoft PowerPoint - prog04.ppt

02: 変数と標準入出力

講習No.12

CプログラミングI

Microsoft Word - Javacc.docx

Microsoft PowerPoint - KHPCSS pptx

PowerPoint プレゼンテーション - 物理学情報処理演習

Transcription:

2012 年度計算機システム演習第 5 回 2012.05.25

高水準言語 (C 言語 ) アセンブリ言語 (MIPS) 機械語 (MIPS) コンパイラ アセンブラ 今日の内容 サブルーチンの実装

Outline } ジャンプ 分岐命令 } j, jr, jal } レジスタ衝突 回避 } caller-save } callee-save

分岐命令 ( 復習 ) } j label } Jump } ラベルの命令へジャンプ j next next } jr $A } Jump Register } レジスタ $A の値の指すアドレスにジャンプ } 例 jr $ra la $t0, next jr $t0 next

サブルーチン (C 言語 ) } main ルーチンからサブルーチン add2 を呼び出す add2 のアドレスへジャンプ 以前実行していたアドレスの次命令のアドレスへジャンプ void main() { int m = 10; int n = 20; int sum = add2(m, m); printf( %d\n, sum); } int add2(int x, int y) { int sum = x + y; return sum; }

} } } サブルーチン呼び出し jal Label } } Jump and Link Label にジャンプすると同時に $ra に次の命令のアドレス ( リターンアドレス ) を保存 j Label は $ra の内容を変えない サブルーチン呼び出し用レジスタ } 引数 $a0 ~ $a3 } 返り値 $v0 ~ $v1 } syscall と同じような使い方 add2 $v0 = $a0+$a1 main.text li $t0, 10 # m=10 li $t1, 20 # n=20 move $a0, $t0 move $a1, $t1 jal add2 # call move $a0, $v0 # syscall で出力 move $a0, $t0 move $a1, $t1 jal add2 # call move $a0, $v0 # syscall で出力 jr $ra add2 # a0->x, a1->y add $t0, $a0, $a1 move $v0, $t0 jr $ra

サブルーチンからの復帰 } jr $ra } $ra レジスタの指すアドレスにジャンプして戻る $ra add2 0x00400024 move $a1, $t1 0x00400028 jal add2 (add2は0x00400044) 0x0040002c move $a0, $v0 $ra = 0x00400002c 0x00400040 0x00400044 add $t0, $a0, $a1 0x00400048 move $v0, $t0 0x0040004c jr $ra

レジスタの衝突 } 呼び出し元と呼び出し先で同じレジスタを使う場合 } サブルーチンが呼び出し元が使っているレジスタを上書き ($t0) } 別のレジスタを使用すればよい? } 外部命令を呼び出す場合は? $t0 を上書き main add2 li $t0, 10 li $t1, 20 move $a0, $t0 #$t0=10 move $a1, $t1 jal add2 (syscallでプリント) move $a0, $t0 #$t0=? move $a1, $t1 jal add2 # a0->x, a1->y add $t0, $a0, $a1 move $v0, $t0 jr $ra

レジスタの使用規則 } 規則に違反したからといってプログラムが実行できないわけではない } もちろん意図しない動作をする可能性はある } 一時レジスタには 2 種類の使用規則がある } ルーチン内で使用する場合 上書きしてよいレジスタ } } 上書きされたくない場合 サブルーチンを呼び出す前に退避が必要 (caller-save) } $t0 ~ $t9, $v0 ~ $v1, $a0 ~$a3 ルーチン内で使用する場合 上書きする前に退避しなければならないレジスタ } 使用する場合 ルーチン内で退避が必要 (callee-save) } $s0~$s7, $ra

レジスタの退避 (caller-save) } 呼び出し元がサブルーチンを呼ぶ前にメモリにレジスタの内容を保存し 終了したら元に戻す サブルーチン実行前 -> サブルーチン終了後メモリレジスタレジスタ $t0 $t0 $t1 保存 $t0 $t1 復元 $t1

レジスタ退避場所 スタックセグメント } メモリのどこにレジスタを保存するか? } 保存用のスタックが用意されている => スタックセグメント } 保存する時にスタックに積む (push) } 復元する時にスタックから取り出す (pop) } $sp レジスタがスタックの先頭アドレスを指している } スタックの先頭に push, pop すればよい push メモリ pop $sp スタックセグメント

レジスタの退避 } } caller-save ではサブルーチン実行前に行う レジスタ退避方法 1. スタックに push する場所を確保 } addi $sp, $sp, -n } } m 個のレジスタを push する時 n = m*4 レジスタ 4 バイト -n するのはスタックはアドレスの高い方 ( 上位 ) から低い方 ( 下位 ) へ伸びるため 0x00000000 新しい $sp 古い $sp スタックセグメント 0xffffffff

レジスタの退避 (cont d) 2. スタックにレジスタの値を push する } sw $x, d($sp) } スタックの先頭から d = 0, 4,... でアクセスできる main addi $sp, $sp, -8 # 2レジスタ *4byte sw $t0, 0($sp) # push $t0 sw $t1, 4($sp) # push $t1 jal add2 $t0 $t1 0x00000000 push $sp+0 $sp+4 0xffffffff $t0 $t1 スタックセグメント

レジスタの復帰 } } サブルーチン終了後に行なう スタックから pop した値をレジスタに代入 1. スタックから値を読み出す } lw $x, d($sp) d = 0, 4,... 2. 不要になったスタック領域を開放する } addi $sp, $sp, n jal add2 lw $t1, 4($sp) # pop $t1 lw $t0, 0($sp) # pop $t0 addi $sp, $sp, 8 # 2レジスタ *4byte jr $ra $t0 $t1 0x00000000 pop 古い $sp 新しい $sp 0xffffffff $t0 $t1 スタックセグメント

レジスタ保存のコード例 main addi $sp, $sp, -8 # 2レジスタ *4byte sw $t0, 0($sp) # push $t0 sw $t1, 4($sp) # push $t1 jal add2 lw $t1, 4($sp) # pop $t1 lw $t0, 0($sp) # pop $t0 addi $sp, $sp, 8 # 2レジスタ *4byte jr $ra add2 対応

add2 を修正 ($t0, $t1 を退避 ) m6.s.text main addi $sp, $sp, -8 # 退避領域作成 li $t0, 10 li $t1, 20 move $a0, $t0 # sum = add2(m, m) move $a1, $t0 sw $t0, 0($sp) sw $t1, 4($sp) jal add2 lw $t1, 4($sp) lw $t0, 0($sp) move $a0, $v0 # printf li $v0, 1 syscall move $a0, $t0 # sum = add2(m, n) move $a1, $t1 sw $t0, 0($sp) sw $t1, 4($sp) jal add2 lw $t1, 4($sp) lw $t0, 0($sp) move $a0, $v0 # printf li $v0, 1 syscall addi $sp, $sp, 8 jr $ra add2 add $t0, $a0, $a1 move $v0, $t0 jr $ra # 領域開放

サブルーチンからの復帰 } main ルーチンの戻りアドレスが上書きされてしまう $ra add2 0x00400036 move $a1, $t1 0x00400040 jal add2 (0x00400060) 0x00400044 move $a0, $v0 #syscall 等 0x00400052 jr $ra 0x00400056 0x00400060 add $t0, $a0, $a1 0x00400064 move $v0, $t0 0x0040006c jr $ra $ra = 0x004000044

main ルーチンの流れ main(argc, argv, envp) [0x00400000] 174 lw $a0 0($sp) # argc 175 addiu $a1 $sp 4 # argv 176 addiu $a2 $a1 4 # envp 177 sll $v0 $a0 2 178 addu $a2 $a2 $v0 179 jal main 180 nop 182 li $v0 10 183 syscall main プログラム終了後にここに戻る 180 の命令のアドレスを $ra に保存 main プログラムにジャンプ main ルーチン

サブルーチンを呼ぶ場合 $ra の退避 } $ra は callee-save } main ルーチンもサブルーチン } jal 命令を呼ぶ時, $ra を退避 } jal 命令で $ra が上書きされてしまうため main jal foo jr $ra foo jal bar jr $ra bar jr $ra $ra を上書き $ra を上書き

完全なレジスタ保存コード例 main addi $sp, $sp, -12 sw $ra, 0($sp) sw $t0, 4($sp) sw $t1, 8($sp) jal bar lw $t1, 8($sp) lw $t0, 4($sp) lw $ra, 0($sp) addi $sp, $sp, 12 } $ra をサブルーチンの先頭で退避 } 最後で復帰 } サブルーチンを呼ばないときは不要 } 必要に応じて $a0 ~ $a3 も退避 } 呼び出し元ルーチンに引数が無い場合は不要

add2 ( 完成版 ).text main addi $sp, $sp, -12 # 退避領域作成 sw $ra, 0($sp) # ra 退避 li $t0, 10 li $t1, 20 move $a0, $t0 # sum = add2(m, m) move $a1, $t0 sw $t0, 4($sp) sw $t1, 8($sp) jal add2 lw $t1, 8($sp) lw $t0, 4($sp) move $a0, $v0 # printf li $v0, 1 syscall m7.s move $a0, $t0 # sum = add2(m, n) move $a1, $t1 sw $t0, 4($sp) sw $t1, 8($sp) jal add2 lw $t1, 8($sp) lw $t0, 4($sp) move $a0, $v0 # printf li $v0, 1 syscall lw $ra, 0($sp) # ra 復帰 addi $sp, $sp, 12 # 領域開放 jr $ra add2 add $t0, $a0, $a1 move $v0, $t0 jr $ra

復習 スタックフレーム } 1 つのサブルーチンが使うスタック領域 } 退避されたレジスタの内容 } $ra, $t0, $t1,... } ローカル変数 } そのサブルーチンの中でだけ使える変数 } 高級言語が使用 } 他のサブルーチンを呼ぶ時の 5 つ目以降の引数 } 4 つ目まではレジスタ $a0 $a3 に入れられる

スタックフレームの作成 破棄 } サブルーチンを呼ぶ時にスタックフレームを作り 終了した時に破棄する } サブルーチンの最初と最後で $sp のアドレスを変更することで明示的に行う } addi $sp, $sp, ±n main 実行時 foo 実行時 bar 実行時 bar のスタックフレーム main のスタックフレーム foo のスタックフレーム main のスタックフレーム foo のスタックフレーム main のスタックフレーム

QtSpim におけるスタック アドレス 値.data で定義したデータ 退避されたレジスタの内容

Callee-save } 呼び出されるサブルーチンが 自分が使用するレジスタの値を退避 復帰する } callee-save という } レジスタ $s0 $s7 } 呼び出し元では $s0 ~ $s7 は自由に使える } $ra も callee-save

add2 を callee-save で実装.text main addi $sp, $sp, -12 # 退避領域作成 sw $ra, 0($sp) # raはcallee save sw $s0, 4($sp) # s0はcallee save sw $s1, 8($sp) # s1はcallee save li $s0, 10 li $s1, 20 move $a0, $s0 # sum = add2(m, m) move $a1, $s1 jal add2 move $a0, $v0 # printf li $v0, 1 syscall move $a0, $s0 # sum = add2(m, n) move $a1, $s1 jal add2 move $a0, $v0 li $v0, 1 syscall # printf lw $s1, 8($sp) # s1 復帰 lw $s0, 4($sp) # s0 復帰 lw $ra, 0($sp) # ra 復帰 addi $sp, $sp, 12 # 領域開放 jr $ra add2 addi $sp, $sp, -4 sw $s0, 0($sp) add $s0, $a0, $a1 move $v0, $s0 lw $s0, 0($sp) addi $sp, $sp, 4 jr $ra

まとめ caller-save } 上書きする場合 退避せず自由に使ってよい } 一時レジスタ $t0 $t9 } 戻り値レジスタ $v0~$v1 foo bar addi $sp, $sp, -8 # $t0 に代入 sw $t0, 4($sp) jal bar lw $t0, 4($sp) # $t0 を使った処理 addi $sp, $sp, 8 jr $ra # $t0 を使った処理

まとめ callee-save } 上書きする場合 退避が必要 } 退避レジスタ $s0~$s7 } 引数レジスタ $a0 ~ $a3 } 戻りアドレスレジスタ $ra foo bar jal bar addi $sp, $sp, -4 sw $s0, 0($sp) # $s0 を使った処理 lw $s0, 0($sp) addi $sp, $sp, 4 jr $ra

まとめ 一時レジスタ ($t, $s) の違い } t レジスタ (t0-t9) } ルーチン内で使用する場合 上書きしてよい サブルーチンを呼び出す前に退避が必要 (caller-save) } s レジスタ (s0-s8) } ルーチン内で使用する場合 上書きする前に退避 使用する場合 ルーチン内で退避が必要 (callee-save) } 使用するレジスタによって プログラムのパフォーマンスに影響

まとめ 効率の違い } レジスタを退避 復帰する回数の違い } どっちのレジスタ 退避法を使うかはパフォーマンス向上のカギ プログラム例 # $x に代入 jal foo jal bar # $x を使って計算 # $x に代入 jal foo # $x を使って計算 jal bar # $x を使って計算 caller-save ($x の退避回数 ) callee-save ($x の退避回数 ) $x は foo の前で退避し bar の後で復帰 (1 回 ) $x は foo と bar の前後で保存 復帰 (2 回 ) $x の退避 復帰は foo と bar で使うかどうかに依存 1 回 (main)+0 2 回 (foo, bar)

課題 ( 遅れても採点いたします )

課題 1 } 1 つの整数値を入力させ 入力された行数だけ数値を図のように表示するプログラムを書け } num= というプロンプトを表示させて から行数を入力させること } 1 行を表示するサブルーチンを作り 繰り返し呼び出すこと } 例 ) $a0 表示する値 & 表示文字数 } $t0~$t9 を使って caller-save で実装せよ } 補足 整数値入力の実装 num=5 55555 4444 333 22 1 li $v0, 5 syscall move $t0, $v0 実行後 $v0 に入力値が入っている

課題 2 } 以下のアルゴリズムに対応するアセンブリコードを書け } main ルーチンからサブルーチン (fact) を呼んで計算 } n は入力プロンプトを設けること } かけ算命令は mul $x, $y, $z ($x = $y * $z) int fact(int n) { if (n == 0) return 1; else return n * fact(n - 1); }

課題 3 } caller-save で書かれた次ページのコードを callee-save で書き直し コードの効率の違いを論じよ } 0 または 1 を 8 回入力させて 8 ビットの 2 進数とみなし それを 10 進数に変換するプログラム } ( 入力 1) 2 7 + ( 入力 2) 2 6 + ( 入力 3) 2 5 + ( 入力 4) 2 4 +( 入力 5) 2 3 + ( 入力 6) 2 2 + ( 入力 7) 2 1 + ( 入力 8) 2 0 } 注意 } 結果を 2 倍しながら入力を足していく } callee-save なのでサブルーチン内で使わないレジスタを退避する必要はない } main ルーチンもサブルーチンであることに注意せよ } main で $s0 $s7 を使うなら 最初と最後で退避 復帰する必要がある

2 進 10 進変換プログラム main loop.text addi $sp, $sp, -12 sw $ra, 0($sp) li $t0, 0 # 結果 li $t1, 0 # i=0 sw $t0, 4($sp) sw $t1, 8($sp) jal read1bit lw $t1, 8($sp) lw $t0, 4($sp) sll $t0, $t0, 1 # 2 倍 add $t0, $t0, $v0 addi $t1, $t1, 1 blt $t1, 8, loop move $a0, $t0 li $v0, 1 syscall lw $ra, 0($sp) addi $sp, $sp, 12 jr $ra # サブルーチン read1bit li $v0, 5 syscall # read_int jr $ra

課題提出 } 〆切 6/8 ( 金 ) 2359 } 提出物 以下のファイルを圧縮もの } ドキュメント (pdf,plain txt,word なんでも可 ) 以下の内容を含めること } 課題 3 の議論 } 課題 1,2,3 の実行結果 } ( もしあれば ) 感想 質問等 } プログラムソース } 課題 1,2,3 ( 適宜コメントを記述すること )