1 / 31

B10 CPU を作る 1 日目 解説

B10 CPU を作る 1 日目 解説. TA 高田正法 mtakada@mtl.t.u-tokyo.ac.jp. はじめに. 下のページに目を通すようにしてください。 http://www.mtl.t.u-tokyo.ac.jp/~mtakada/jikken_b10/ このスライドも上記の場所にあります。. 今日説明する内容. 実験の目的、内容 この実験で扱う道具について SPIM MIPS アーキテクチャ 課題 1 ~ 3 を行うために必要な知識 レジスタ 命令 システムコール MIPS 用プログラム記述の例. 実験の目的.

andrew
Download Presentation

B10 CPU を作る 1 日目 解説

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. B10 CPUを作る1日目 解説 TA 高田正法 mtakada@mtl.t.u-tokyo.ac.jp

  2. はじめに • 下のページに目を通すようにしてください。 • http://www.mtl.t.u-tokyo.ac.jp/~mtakada/jikken_b10/ • このスライドも上記の場所にあります。

  3. 今日説明する内容 • 実験の目的、内容 • この実験で扱う道具について • SPIM • MIPSアーキテクチャ • 課題1~3を行うために必要な知識 • レジスタ • 命令 • システムコール • MIPS用プログラム記述の例

  4. 実験の目的 • RISC型プロセッサの構造、動作を理解する • 命令セットを理解する • 命令をMIPSシミュレータ”SPIM”に追加することによって、プロセッサの動作に関する理解を深める

  5. 実験の内容 • MIPSの命令セットを理解する • アセンブラでプログラムを書く • 課題1~3 • プロセッサの動作を理解する • 構成図を見て考える • 課題4~5,8 • シミュレータを用いて、命令追加を行う • 課題6~7 • シミュレータと実機の違いについて考える • 課題8

  6. SPIMとは? • RISCプロセッサ MIPS R2000のシミュレータ • 以下の機能をサポート • アセンブリ言語からの直接読み込み • プロセッサの状態表示 • ステップ実行 • 簡単な入出力

  7. MIPSとは? • RISC型プロセッサの一種 • 機能が単純な命令のみを持ち、複雑な機能は命令の組み合わせでサポートする • メモリを扱う命令が、他の命令と分離されているのが特徴 • 32個の32bitレジスタを持つ • レジスタ:計算をするための作業領域

  8. メモリとレジスタの違い • メモリ • ○ 大きい(2^32Byteなど) • ○ アクセスする領域(アドレス)も変数 • × 演算命令で直接扱えない • × 遅い • レジスタ • ○ 演算命令で直接扱える • ○ 速い • × 小さい(32bitレジスタが32個) • × アクセスする領域(レジスタ番号)は命令内で明示

  9. レジスタの種類(1) – 汎用レジスタ • $t0~$t9 • ユーザー用のレジスタ • サブルーチン(関数)を呼び出す際には、呼び出す側で値を保存しておく必要がある • $s0~$s7 • ユーザー用のレジスタ • 呼び出されたサブルーチン側で、中身を保存する必要がある

  10. レジスタの種類(2) – 関数呼び出し用 • $a0~$a3 • サブルーチン(関数)を呼び出す際に、引数をこれに入れる • $v0~$v1 • サブルーチン(関数)からの戻り値をここに入れる • $ra • サブルーチン(関数)を呼び出した側の、プログラム番地を保存する

  11. レジスタの種類(3) – 特殊なレジスタ • $zero • 常に0が入っているレジスタ • $sp • スタックの先頭のアドレスが格納されるレジスタ

  12. レジスタの種類(4) – 使わないもの • 使ってはいけないレジスタ • $at • 疑似命令を展開する時に使われるレジスタ • ここでいう疑似命令: ソースファイルに書くことが可能であるが、実際には複数の実在する命令に展開される命令のこと(例:blt) • $k0~$k1 • OS予約レジスタ • 気にしなくて良いレジスタ • $gp, $fp

  13. プロセッサの命令の種類 • メモリ←→レジスタのデータのやり取りをする命令 • いわゆるload/store • レジスタを用いて計算をする命令 • 算術演算、論理演算その他 • 次に実行する命令を変える命令 • 条件分岐命令 • C言語のif, for, whileなどで使われる • 無条件ジャンプ命令 • C言語での関数呼び出しなどで使われる

  14. load/storeの例 1Word(32bit) 1Word(32bit) 1Byte 1Byte 1Byte 1Byte 1Byte 1Byte 1Byte 1Byte x x+1 x+2 x+3 x+4…(番地) • lw $t0, 4($t1) • メモリの($t1 + 4)番地に書かれている値(32bit)を、$t0レジスタに格納する • $t0 = *($t1 + 1); • +1 なのは、+4番地=32bit向こう=1要素進んだところだから • sw $s2, 0($t0) • $s2の中身(32bit)を、メモリの($t0+0)番地に格納する • *($t0) = $s2;

  15. 演算命令の例 • addi $t0, $t1, 1 • $t0 = $t1 + 1; • or $s0, $s1, $s2 • $s0 = $s1 | $s2;

  16. 制御命令の例 • bne $t0, $t1, LABEL • $t0 != $t1 ならば、次からは、LABEL番地から始まる命令列を実行する • if( $t0 != $t1 ) goto LABEL; • jal LABEL • $raに、jal命令の番地+4を格納し、次からはLABEL番地から始まる命令列を実行する • サブルーチン(関数)呼び出しに使われる

  17. syscallの使い方 • SPIMでは、キーボードからの入力/画面への出力を、syscallを使って行います • $v0にシステムコール番号を入れることによって、数種類の機能を実現できます • 詳しくは、SPIMマニュアルの8ページを参照してください

  18. システムコールの例 • $t0(整数型)の中身を画面に表示 • li $v0, 1 # $v0 = 1; • move $a0, $t0 # $a0 = $t0; • syscall • メモリの$t0番地から始まる文字列を表示 • li $v0, 4 # $v0 = 4; • move $a0, $t0 # $a0 = $t0; • syscall • プログラムの実行を終了 • li $v0, 10 • syscall

  19. MIPS用プログラムの記述例

  20. 具体例 • このような関数を考えましょう • numという配列が渡されたときに、先頭n要素の和を返す関数 int sum(int n, int num[]){ int sum = 0; int i; for( i = 0; i < n; i++ ){ sum += num[i]; } return sum; }

  21. C言語からアセンブリ言語へ • C言語の変数は、主に2種類 • static変数 • プログラムのどこからでも見ることのできる変数 • コンパイル時に、静的にメモリに割り当てられる • local変数 • 同じ関数内でのみ参照可能 • 実際には以下のいずれかに割り当てます • レジスタ ←ほとんどこちらだけで事足ります • メモリのスタック領域(※坂井先生の資料8ページ参照)

  22. ソースファイルの書式 .data #お約束 ここに、static変数に対応する部分を ”.word”等の疑似命令を使って書く .text #お約束 .globl main #お約束 main: #お約束 ここからプログラムを書く # “#”から行末まではコメントになります

  23. for文の展開 • for( i = 0; i < n; i++)をアセンブリ言語で書きましょう • nは、$a0に入っていると仮定 • iは$t0に割り当てましょう li $t0, 0 # i = 0; loop_start: 何か処理… addi $t0, $t0, 1 # i++ bne $t0, $a0, loop_start # if( i != n ) goto loop_start;

  24. メモリからの読み出し • $a1に、先頭の要素のアドレスが入っていると仮定しましょう • $t1に、現在の要素のアドレスを入れましょう • $t2に、各要素の値を一時的に格納しましょう • $v0に、合計の値を格納しましょう li $t0, 0 # i =0; li $v0, 0 # sum = 0; move $t1, $a1 # $t1 = $a1; loop_start: lw $t2, 0($t1) # $t2 = *($t1); add $v0, $v0, $t2 # $v0 = $v0 + $t2; addi $t1, $t1, 4 # 次の要素は4番地(32bit)先 addi $t0, $t0, 1 # i++; bne $t0, $a0, loop_start # if( I != n ) goto loop_start;

  25. 関数ができました sum: li $t0, 0 # i =0; li $v0, 0 # sum = 0; move $t1, $a1 # $t1 = $a1; loop_start: lw $t2, 0($t1) # $t2 = *($t1); add $v0, $v0, $t2 # $v0 = $v0 + $t2; addi $t1, $t1, 4 # 次の要素は4番地(32bit)先 addi $t0, $t0, 1 # i++; bne $t0, $a0, loop_start # if( i != n ) goto loop_start; jr $ra # 関数呼び出し元へ

  26. この関数の仕様 • 配列に入っている各要素の和を計算する • $a0: 要素数 • $a1: 先頭のアドレス • $v0: 計算結果

  27. 呼び出し元を書きましょう • こんなプログラムだとしましょう int numOfElements=4; // static変数 int elements[] = {1, 2, 3, 4}; // static変数 void main(){ int s = sum( numOfElements, elements); printf( “%d”, s); }

  28. 呼び出し元 main: lw $a0, numOfElements # $a0 = numOfElements; la $a1, elements # $a1 = &(elements[0]); jal sum # $v0 = sum($a0, $a1); move $a0, $v0 # $a0 = s; li $v0, 1 # syscall # prinf(“%d”, s); li $v0, 10 syscall # exit();

  29. static変数部分 • 今回は、numOfElementsとelementsがstatic変数 .data numOfElements: .word 4 # int numOfElements=4; elements: .word 1, 2, 3, 4 # int elements[]={1, 2, 3, 4}; これで、numOfElementsが”4”の入ったアドレス、elementsが1, 2, 3, 4が入ったメモリの先頭のアドレスを指すようになります

  30. 完了 • http://www.mtl.t.u-tokyo.ac.jp/~mtakada/jikken_b10/にあるsum.sがこのプログラムの完成品です • SPIMで読み込んで、実行してみましょう • .word部分の値を変えて、結果が変わることを確認してみましょう

  31. 駆け足になりましたが • 各内容についての詳細は以下を参照してください • レジスタの一覧 • SPIMマニュアル 10ページ • 命令の一覧 • SPIMマニュアル 13ページ~ • システムコールの一覧 • SPIMマニュアル 8ページ~ • .data部分に書くことのできるもの • SPIMマニュアル 7ページ~

More Related