卒 業 研 究 報 告

題目32 ビットRISC プロセッサの設計

指 導 教 員
矢野 政顯

教授

報 告 者
松見 隆之

平成

14 年

2 月

7 日

高知工科大学 電子・光システム工学科

目次
第１章

はじめに

1

第２章

RISC アーキテクチャ

2

2.1
2.2
2.3
2.4
2.5
2.6
2.7
2.8
2.9
2.10
2.11

RISC アーキテクチャとは
パイプライン方式
ロード＆ストア方式
RISC の命令形式
アドレッシングモード
データ形式
高度メモリ管理システム
スーパースカラ方式
動的パイプラインスケジューリング
例外
R3000 の命令コード

2
2
5
5
7
10
11
13
14
15
16

第３章

プロセッサの設計

19

3.1
3.2
3.3
3.4
3.5
3.6

命令の選別
プログラムカウンタ設計
ALU 基本仕様設計
CPU レジスタ仕様設計
その他機能部の設計
データパス設計

19
22
24
30
34
41

VHDL 記述

第４章
4.1
4.2

各機能ブロックの記述
シミュレーションおよびその考察

第５章

まとめ

45
45
70

78

謝辞

79

参考文献

80

付録

第1章

はじめに

今日、コンピュータだけではなくほとんどの情報端末にプロセッサが搭載されている。プロセッサの中でも RISC(Reduced Instruction Set Computer)アーキテクチャを採用したものは、ワークステーション、ゲーム機等々さまざ
まな製品に広く使用されている。また、ほとんどのプロセッサがこの RISC 方式を採用し、RISC はプロセッサの標準ともいえる存在になっている。RISC は従来の CISC(Complex Instruction Set Computer)と異なり、回路を簡単にし、コンパイラを通して高級プログラム言語との親和性が高まるように設計され、またパイプライン方式およびロード＆ストア方式を採用することで処理
効 率 を 高 め て い る 。大 学 院 で 研 究 に 必 要な 中 央 処 理 装 置 （ CPU(Central
Processing Unit)）技術習得のため、卒業研究として、RISC アーキテクチ
ャに基づいたプロセッサの設計を行った。本論文の第２章では RISC アーキテク
チャの概要について、第３章には卒業研究で取り上げたプロセッサの設計について、第４章では設計したプロセッサの VHDL(Very High Speed Integrated
Circuit)記述およびテストについて述べるとともに、第５章では本研究によって得られた成果を要約し、今後に残る課題に言及する。

1

第2章

RISC アーキテクチャ

2.1 RISC アーキテクチャとはRISC 登場までコンピュータアーキテクチャは CISC という複雑なアー
キテクチャによって占められていた。この CISC アーキテクチャは細かいレベルでの演算が可能であり、高級言語および OS(Operating System)
を強力に支援する。そして回路規模が上昇し、相次ぐ機能追加でますま
す複雑になっていた。しかしながら CISC はその構造上常にプロセッサ内部速度から比べると遅いメインメモリとアクセスするだけではなく回路が大変複雑で回路規模が大きいため高速化に向かなかった。それと比較して RISC は統計的な分析を元にソフトウェア、ハードウェアの機能分担が明確になっている。RISC におけるハードウェアの制御は、CISC がマ
イクロプログラムを利用しているのと違い、すべてコンパイラから行う。
理由としては近年コンピュータ用の言語が複雑になっている。それだけではなく半導体メモリの技術が進歩し、マイクロプログラム用 ROM(Read
Onry Memory)ではなく、高速の RAM(Randam Access Memory)の実装が可能になったことからソフトウェアからの直接制御が可能になったためである。
RISC(Reduced Instruction Set Computer)はその名のとおり簡
易命令セットコンピュータである。上にも述べたがコンパイラから吐き出されるコードを統計的に分析し、それをもとに必要のない命令を削る
ことによって回路を単純にしている。また、RISC は１クロック１命令を目標に設計され、そのためにパイプライン等のさまざまな方式を導入している。

2.2 パイプライン方式
命令の実行に際してある一定の時間が必要である。これを減らす手法
としてパイプラインが上げられる。パイプラインとは命令をいくつかの部分に分割して、順番に多数の命令が実行される場合に、部分ごとに複数の命令を同時に実行する方式である。 例として図 2.1 に示すような

2

５ステージのパイプラインがあげられる。この場合、命令実行に必要なサイクル数は５サイクルである。
IF

RR

EX

MA

RW

命令実行方
向

図2.１ 命令パイプライン

第１サイクル（IF(Instruction Fetch)）は命令のフェッチ部である。プログラムカウンタで指示されたアドレスに格納されている命令を読み取る。第 2 サイクル（RR(Register Read)）はレジスタリード部である。フェッチした命令の中に含まれるアドレスから対象のデータを読み出す。第 3 サイクル（EX(Execute)）は演算部である。ここでは読み出されたデータと命令を元に ALU(Arithmetic Logic Unit)で演算を行う。第 4 サイクル(MA(Memory Access)はメモリアクセス部である。
ここではメモリへの書込み、読み出しを行う。最後のサイクル（RW(Register Write)）では演算結果や、メモリより読み出したデー
タをレジスタに格納する。
このように処理を５分割にすることで、そのまま実行すれば５サイク
ル必要な命令を、１クロックあたり１命令の割合で実行できることにな
る。ベルトコンベアーのように各部分で処理を分担し専念させることで、総合的に見て同時に５個の命令を実行できることになる。パイプラインを採用していない場合、１命令に５サイクル必要な命令では処理が非常に低速である。

IF

RR

EX

MA

RW

IF

RR

EX

MA

RW

IF

RR

EX

MA

RW

IF

RR

EX

MA

RW

IF

RR

EX

MA

サイクル

命令実行

図2.２ 命令パイプライン

3

RW図 2.2 に示すように５段の深さのパイプラインを使用することによって命令サイクルを減らすことができる。しかし、直前の命令の演算結果に応じた条件分岐が必要な場合、パイプラインの命令実行を遅らせなけ
ればならない。例えばに図 2.3 のような４段パイプラインの場合、以下のようになる。
必要とされるデータ

遅延
スロット

データを必要とする命令

命令実行

図2.3 遅延スロット
この例では、最初の命令の第 4 ステージで、次に実行される命令のデータを格納するが、次の命令の開始時点では最初の命令の結果が格納されていないので実行できない。このため要求されるデータが使用可能になるまで遅延スロット（NOP 命令）を次の命令との間に入れなければならない。したがってパイプラインによってサイクル数を減らしても、このような場合にはその利点が生かされない。このためパイプライン管理
ではパイプラインの流れを妨害する可能性のある命令（Branch 命令、Jump 命令）をコンパイラによって正しく効率よく管理する必要である。
上記の例では、命令長および処理時間を一定としていたが、仮にそれらが可変であった場合には、パイプラインにおける効率のよいスケジュー
ル管理はほぼ不可能である。このため、RISC において１サイクル１命令を実現するためには必ず命令および部分ごとの命令実行時間は一定である必要がある。

4

2.3 ロード＆ストア方式
CISC において処理速度を高速化できなかった大きな理由は 2.1 節で述べたとおりメモリアクセス速度である。メインメモリへのアクセスは
内部メモリと比べて速度が遅く余分なサイクルが使われるため RISC ではロード＆ストアアーキテクチャを採用し、命令実行の結果は必ずレジスタに格納ように設計されている。メインメモリへのアクセスはメモリ
アクセス命令（Load 命令、Store 命令）によってのみ行われる。それにより、１命令ごとにメインメモリにアクセスする必要性がなくなるため、パフォーマンスが向上する。
表 2.1

RISC と CISC の違い

RISC
CISC
メモリアクセス
専用命令のみ
大半の命令
レジスタ
多数の汎用レジスタ 用途固定のレジスタ
演算結果格納レジスタ
メモリ

2.4 RISC の命令形式
RISC と CISC の大きな違いは命令長の違いであることは上で述べたとおりである。RISC では固定幅の命令長を実現するために多数ある命令形
式のうちから３種類の命令形式だけを採用している。第１は主に演算等を高速に行うための R 形式（Register 形式）、第２は直接データ入力の可能な演算形式であり、且つメモリの制御が可能な I 形式（Immediate
形式）、第３は命令のジャンプのために使われる J 形式（Jump 形式）である。

2.4.1 R 形式

R 形式の命令は３つのオペランドを持っており、これらのオペランド間で演算を行う。ただし、３つのオペランド全てが直接演算可能な値ではないのでオペランドを数値に変換する必要がある。変換方法については

5

後に述する。それぞれのオペランドは各々名前をもっており命令コードの 25 ビ ッ ト 〜 21 ビ ッ ト 目 ま で を ソ ー ス レ ジ ス タ （ RS(Source
Register)）、20 ビット〜16 ビット目までをターゲットレジスタ（RT(Target Register)）、15 ビット〜11 ビット目までをデスティネーションレジスタ（RD(Destination Register)）という。機能としてはソースレジスタおよびターゲットレジスタがそれぞれ演算する値、演算される値の格納場所を指示し、デスティネーションレジスタは演算された結果を格納する場所を示している。R 形式命令のオペランド以外のビットは 31 ビット〜26 ビット目がオペレーションコード(Operation
Code)、10 ビット〜６ビット目がシフト数(Shamt)、５ビット〜０ビッ
ト目が ALU 機能コード(ALU Function Code)を表している。通常 R 形
式の命令のオペレーションコードおよびシフト数はすべて０であり、どのように演算するかの判別は ALU 機能コードをもとに行われる。

31

26 25
OP

21 20
RS

16 15
RT

図2.4

11 10
RD

6 5
Shamt

0
Function

R形式ビット配列

2.4.2 I 形式

I 形式の命令は２つのオペランドおよび１つの Immediate と呼ばれる数を持っている。２つのオペランドは R 形式と同じく直接演算可能な数ではないので、データー格納場所をアドレスに変換する必要がある。また、Immediate は直接演算可能な数であるが、RISC において演算および デ ー タ は 常 に 32 ビ ッ ト に 固 定 さ れ て い る た め 、 16 ビ ッ ト のImmediate も 32 ビットに変換する必要がある。
命令の 25 ビット〜21 ビット目をソースレジスタ（RS）、20 ビット〜16
ビ ッ ト 目 を タ ー ゲ ッ ト レ ジ ス タ （ RT ）、15 ビ ッ ト 〜 ０ ビ ッ ト 目をImmediate といい、RS は演算される数として、Immediate は演算する数として主に機能する。また、ターゲットレジスタは R 形式のデスティ
ネーションと同じく演算結果を格納する場所である。オペランド使用法の例外として Branch 命令、Store 命令がある。Operation Code の
位置は R 命令と同じで、どのような演算を行うかの判別は R 形式と異な

6

り Operation Code を元に行う。

31

26 25
OP

16 15

21 20
RS

0

RT

図2.5

Immediate

I形式ビット配列

2.4.3 J 形式

J 形式は他の形式と大きく異なり演算を実行しない。そのためオペラン
ドは無く、26 ビットの Address と Operation Code のみである。RISC
におけるメモリアドレスは 32 ビットのため、この Address はこのままは使用できない。このため 32 ビットに拡張される。拡張後のアドレスを
ジャンプ先アドレスとしてジャンプするものである。
31

26 25

0

OP

Address

図2.6

J形式ビット配列

2.5 アドレッシングモード
RISC の命令長は 32 ビットに固定されているため、32 ビットのオペラ
ンドを直接扱うことはできない。そのため RISC では以下の４通りのアクセス方式を採用している。

2.5.1 小さな定数のオペランド

実際のプログラムでは定数を使用した演算は比較的多く使用されている。C 言語での FOR 文や While 文、IF 文では小さな定数を扱う場合が7

ほとんどである。実際にプログラムを組む場合このような命令を多用するので、ますます小さな定数を扱う機会は増える。そのため RISC では
Immediate という方法で小さな定数を直接扱えるようにしている。もちろん RISC での命令長や数値幅は 32 ビット固定なので 16 ビットのImmediate を 32 ビットに拡張して使用する。
例えばに 10 進数で-550 という値を RISC で扱う場合には次のようになる。
-550[10]=11111101110110102
なので Immediate はImmediate=1111110111011010となる。これに 16 ビット分の０を付加し、DATA=00000000000000001111110111011010とすると、この 32 ビットの値は、10 進数に直すと000000000000000011111101110110102=6498610となり、正しくない。これは負の値に２の補数表現を用いているためである。２の補数表現に対応させるために単なる拡張ではなく符号拡張を使用しなければならない。符号拡張は次のプロセスで行う。
① Immediate の先頭１ビットを見る② 先頭１ビットを 16 ビット分結合
上記の例の場合-55010 なので符号拡張を行うとDATA=11111111111111111111110111011010
となる。
16

32

Immediate

符号拡張

DATA

図2.7 符号拡張
2.5.2 分岐命令用のオペランド

プログラム中での分岐命令はその分岐先が比較的近くにかかれている場合が多い。そのため、分岐命令でのアドレッシングでは PC 相対と呼ばれるものを使用し、PC の値と Immediate との和をとることで、効率よ8く分岐できるようにしている。
① Immediate の値を符号拡張する② PC の値と拡張後の Immediate の値との和をとる③ 結果をアドレスとする
仮に現在プログラムカウンタと Immediate の値がPC=000000000000000000000001111101002=50010
Immediate=00000011111010002=100010の場合、必要なアドレスはAddress=000000000000000000000101110111002となる。
16

Immediate

加算

アドレス

PC

図2.8 PC相対アドレス32

命令におけるこのようなアドレッシングは PC 相対アドレッシングとよばれる。

2.5.3 ジャンプ命令用のオペランド

ジャンプ命令においてもジャンプ先はある程度近くに置かれている場合が多い。分岐命令では分岐条件を指定するための Immediate が 16 ビ
ットに制限されていたが、ジャンプ命令では、特に条件を指定する必要が無いため、入力できる DATA は 26 ビットである。
例を 2.5.2 節と同じとした場合ジャンプ先アドレスはAddress=000000000000000000000011111010002

9

となる。
26

入力Address

加算

アドレス

図2.9 J命令用擬似直接アドレスPC

32

2.5.4 R 命令のオペランド

R 形式命令のデータ方式はレジスタ・アドレッシングといわれる。命令の中の５ビットで指定されたレジスタの中にあるデータを読み出し、それを演算に使う。
5

アドレス

32

レジスタ

データ

図2.10 レジスタアドレッシング

2.6 データ形式
RISC において、取り扱い可能なデータ形式は 32 ビットワード、16 ビットハーフワード、8 ビットバイトである。全てのメモリは 32 ビットで扱われるために、バイトの取り扱いには一定の決まりがある。1 つはビッ
グエンディアン、もう一つがリトルエンディアンである。

10

●ビッグエンディアンを使用する場合。
システムを全てビッグエンディアンで構成する場合には、バイト番号０は必ず 32 ビットの最上位である。32 ビット目から８ビット区切りにバイト番号０〜３と割り振る。この方式をとる代表的な CPU にはモトローラ社の 68000 が挙げられる。
31

24 23
0

16 15
1

図2.11

8 7
2

0
3

ビッグエンディアン構成●リトルエンディアンを使用する場合。
システムをリトルエンディアンで構成する場合、バイト番号０はビッ
グエンディアンと異なり最下位バイトである。32 ビット目から８ビット
区切りにバイト番号３〜０が割り振られる。この方式を採用している CPU
としては X86 や DEC 社製品が挙げられる。
31

24 23
3

16 15
2

図2.12

8 7
1

0
0

リトルエンディアン構成

2.7 高度メモリ管理システム
RISC には TLB(Translation Lookaside Buffer)）（アドレス変換バッファ）を採用したメモリ管理ユニットを内蔵し、物理アドレスでは実現不可能な大容量の仮想アドレスとの変換を高速に行っている。通常、メモリにアクセスするためには、一度メモリにアクセスしてその情報を取得し、それをもとにデータアクセスを行う。このままではレジス
タに比べて低速なメモリアクセス時間が２倍になってしまい非常に非効率的である。そのため、メモリアドレス変換を記録しておく専用のメモ
リ（TLB）が搭載されている。

11

32 ビットで構成された仮想アドレス空間形式では、上位 20 ビットは
仮想ページ番号として動作し、下位 12 ビットは TLB に渡されて物理ア
ドレスとの変換に使用される。仮想ページ番号のうちの上位３ビットをメモリのモード指定に使用する。

2.7.1 ユーザーモードでのアドレス指定

RISC には特権状態としてカーネルモードとユーザーモードがある。通常はユーザーモードで処理されているが、例外が発生した場合のプロセ
ッサはカーネルモードで動作する。
ユーザーモードで動作している場合には、取り扱い可能な仮想メモリ空間として、2G バイトの空間が用意されている。アドレス指定は先頭ビットが常に０であるほかは通常のアドレス指定と同じである。このため、扱えるアドレスは 0000000~7FFFFFF である。TLB を使ってこの空間をどちらのモードからでも同じようにマッピングできる。この空間はデー
タ格納のみに使われる。

2.7.2 カーネルモードでのアドレス指定

プロセッサが例外を起こしカーネルモードで動作している場合、プロセッサはユーザーモードのメモリ空間以外に３種類のメモリ空間を使用できる。
KSEG0：このアドレス空間は 512M で TLB を使用しない。またこの空間
へのアクセスにはキャッシュが用いられる。命令実行コードの一部とそのデータを格納するのに主に使用される。
KSEG1：このアドレス空間は 512M で TLB を使用しない。KSEG0 と違う
点はキャッシュを使用しないことである。用途としてはディスクバッフ
ァや ROM として使用される。
KSEG2；このアドレス空間は 1024M である。他の空間と異なりこの空間
では TLB を使用し、仮想メモリを任意の物理アドレスにマッピングできる。主な用途は、メモリマップやスタックである。

12

2048M

512M

512M

1024M

ユーザ空間

KSEG0

KSEG1

KSEG2

仮想メモリ

TLB

メモリ

メモリ

512M

3684M

図2.13

物理メモリ

メモリマップ

2.8 スーパースカラ方式
コンピュータの性能を上げていく手法として、パイプライン方式は既に述べたとおりである。この他の方法としてコンピュータ内部の構成を多重化して、一度に処理できる命令数を増やす手法がある。この方式はスーパースカラ方式と呼ばれている。RISC ではこの方法を実現し、CPUによってさまざまな多重化を施している。仮に、2 重スーパースカラを考えるとする。RISC 命令の中でもっとも頻発し、かつもっとも時間のかかる命令は Load 命令、Store 命令である。この命令をもう一つのパイプラインで実行することで圧倒的に効率を上げられる。

13

算術命令

IF

RR

EX

MA

RW

LOAD命令STORE命令

IF

RR

EX

MA

RW

算術命令

IF

RR

EX

MA

RW

LOAD命令STORE命令

IF

RR

EX

MA

RW

算術命令

IF

RR

EX

MA

RW

LOAD命令STORE命令

IF

RR

EX

MA

RW

命令実行

図2.14

スーパースカラのパイプライン

2.9 動的パイプラインスケジューリング
動的パイプラインスケジューリングでは、ストールする場合、ストール解消までの処理中にその先の命令より実行可能な命令を選び出し、実行する。そのためにはパイプラインを機能ごとに分割しなければならない。各ユニットにはリザベーションバッファを持ち、ここで、命令操作とオペランドを保持する。このバッファに全てのデータが整い、実行可能となれば命令が実行され、確定ユニットを通して結果をストアする。
普通はパイプライン通して命令を順序どおりに実行しメモリに書き込む。
この方式をイン・オーダー完了という。一方、機能ユニットは命令処理を好きなときに開始、終了させて良いのでこれを許すやり方としてアウト・オブ・オーダー完了がある。ただし、この方法の場合には割り込みが不正確になってしまうという欠点がある。またこの動的パイプライン処理というのは従来の静的パイプラインと比べて圧倒的に設計が難しい。
これは、動的なスケジューリングは分岐予測と併用して使用される場合が多いためである。もちろん分岐予測なので、予測が外れた場合には全ての実行ユニットで分岐命令以降に実行されていた命令の結果を破棄しなければならない。この方法はスーパースカラを伴う場合が多いので場合によっては結果が確定してしまっている可能性があるからである。こ14

のように併用して演算を行う方法を投機的実行という。
IF/RR

リザベーション
バッファ

リザベーション
バッファ

機能ユニット機能ユニット

確定ユニットWB

図2.15 動的スケジューリングにおける機能ブロック

2.10 例外
プロセッサはさまざまな命令を処理するため予期しないところで予想外の動作を起こす場合がある。それを例外としてプロセッサでは処理を行う。まず、正常な命令の流れに割り込みをかけ、例外を起こした命令
を異常終了させる。それと同時にパイプラインで処理されていた命令もすべて異常終了させ、プロセッサは例外処理プログラムへジャンプする。
●アドレスエラー例外
この例外は、データアドレスのワード境界がずれた状態で Load、Store または命令をフェッチで発生する。メモリアドレスのワードはす
べてアドレスの最下位２ビットが 00 でなければならない。この例外は致命的例外である。
●ブレークポイント例外
この例外はプロセッサがブレーク命令を実行した場合に発生する。この例外が発生した場合には該当するシステムルーチンに制御を渡す。
●バスエラー例外
この例外は CPU に対して外部からのエラー入力があった場合に発生する。例としてバスがタイムアウトした場合、パリティエラーがあった場

15

合があげられる。
●コプロセッサ使用不可能例外
プロセッサがコプロセッサを利用をしようとした際、コプロセッサが利用可能でない場合に発生する。
●割り込み例外
この例外はハードウェア若しくはソフトウェアからの割り込みがあった場合に発生する。
●オーバーフロー例外
この例外はもっとも基本的な例外で、算術命令を実行した際、実行中にオーバーフローした場合に発生する。例外処理ルーチンで適切に処理された後、カーネルは実行プロセスに対してオーバーフローエラーを通知する。
●予約命令例外
この例外は命令が存在しない命令だった場合、すなわち、Operation
Code および ALU Function Code に該当するコードが無かった場合に発生する。例外処理ルーチンは実行プロセスに対して違法命令を通知する。
●リセット例外
この例外はプロセッサの入力信号に RESET が入った場合に発生する。
この例外の操作としてはすべてのレジスタ、コプロセッサ、キャッシュ、およびメモリを初期化し、その後診断処理等が行われオペレーティング
システムに移る。
●システム呼び出し例外
この例外は SYSCALL 命令特有のもので、適切な例外処理の後、オペレーティングシステムは該当するプロセスに制御を渡す。
●TLB に関する例外
この例外は仮想ページ番号が TLB のどれにもヒットしなかった場合や、ヒットしても Valid,Dirty 等の信号が出ている場合に発生する。

2.11 R3000 の命令コード
RISC アーキテクチャをとっている CPU である R3000 の命令には次の命令が存在する。[1]● ADD 命令
● ADDI 命令

加算命令
Immediate 型加算命令

16

●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●

ADDIU 命令ADDU 命令
AND 命令ANDI 命令BCZF 命令BCZT 命令
BEQ 命令BGEZ 命令BGEZAL 命令
BGTZ 命令
BLEZ 命令
BLTZ 命令
BLTZAL 命令
BNE 命令BREAK 命令
CFCZ 命令
COPZ 命令CTCZ 命令
DIV 命令DIVU 命令
J 命令
JAL 命令JALR 命令
JR 命令
LB 命令
LBU 命令LH 命令
LHU 命令LUI 命令LW 命令
LWCZ 命令LWL 命令LWR 命令MFC0 命令
MFCZ 命令MFHI 命令

Immediate 型無符号加算命令
無符号加算命令
論理積命令
Immediate 型論理積命令
コプロセッサ Z が False 分岐
コプロセッサ Z が True 分岐
等号成立分岐命令
ゼロ以上分岐
状態保存ゼロ以上分岐
正の数分岐
ゼロ以下分岐負の数分岐
状態保存負の数分岐
不等号分岐
ブレーク
コプロセッサからの制御移動
コプロセッサ命令
コプロセッサに制御移動
除算
無符号除算命令ジャンプ
状態保存ジャンプ
状態保存レジスタジャンプ
レジスタジャンプ
バイトロード
無符号バイトロード
ハーフワードロード
無符号ハーフワードロード
上位に Immediate ロード
ワードロードコプロセッサワードロード
ワードの左ロード
ワードの右ロードシステム制御コプロセッサからの転送
コプロセッサからの転送
HI レジスタからの転送

17

●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●

MFLO 命令
MTC0 命令
MTCZ 命令MTHI 命令MTLO 命令
MULT 命令MULTU 命令
NOR 命令OR 命令
ORI 命令RFE 命令
SB 命令
SH 命令
SLL 命令SLLV 命令
SLT 命令SLTI 命令SLTIU 命令SLTU 命令
SRA 命令SRAV 命令
SRL 命令SRLV 命令
SUB 命令SUBU 命令SW 命令
SWCZ 命令
SWL 命令SWR 命令SYSCALL 命令
TLBP 命令TLBR 命令TLBWI 命令TLBWR 命令
XOR 命令XORI 命令LO レジスタからの転送
システム制御コプロセッサへの転送
コプロセッサへの転送
HI レジスタへの転送
LO レジスタへの転送
乗算
無符号乗算
否定論理和
論理和
Immediate 論理和
例外からの復元
バイト格納
ハーフワード格納
論理左シフト
論理変数左シフト
未満セット
Immediate 未満セット
Immediate 無符号未満セット
無符号未満セット
算術右シフト
算術変数右シフト
論理右シフト
論理変数右シフト
減算
無符号減算
ワード格納
コプロセッサワード格納
ワード左方向格納
ワード右格納システムコール
TLB エントリ一致
TLB 読み取り
TLB 書込み
ランダム TLB 読み込み
排他的論理和Immediate 排他的論理和

18

第３章
3.1

プロセッサの設計

命令の選別

3.1.1 プロセッサ要求仕様の決定
本研究で設計したプロセッサの仕様は次のとおりである。
方式
命令長
データ長
命令形式

レジスタ数
パイプライン

演算能力

命令処理能力演算方式

MIPS-RISC 互換 Load&Store 方式
固定 32Bit
固定 32Bit
R 形式（3 オペランド方式）
I 形式（2 オペランド Immediate 方式）
J 形式（Jump 命令専用方式）
32Bit 汎用レジスタ 32 個
５段パイプライン
フェッチステージ：命令の読み込みを行う
命令デコードステージ ：レジスタアクセスを行う
命令実行ステージ：演算を行うメモリステージ：メモリへのアクセスを行う
格納ステージ：レジスタへの格納を行う
基本算術演算（加算、減算）
基本論理演算（AND、OR、XOR、NOR）
大小比較演算１クロック当り１命令
単一クロックサイクル方式

まず、RISC 最大の特徴であるパイプライン処理および１クロック当り
１命令の演算を実現することにした。回路が大規模になり、限られた時間の内で実現不可能と思われた TLB や浮動小数点演算ユニットの採用は断念した。また浮動小数点演算ユニットを内蔵しているシステム制御コプロセッサも搭載しないこととした。システム制御コプロセッサの中には乗算、除算制御のためのユニットや、さまざまな例外処理レジスタが19

含まれているが、それらも搭載しないこととした。さらに、RISC を採用
するさまざまなプロセッサで使われているスーパースカラや投機的実行、
およびマルチサイクル方式も採用しないものとした。
3.1.2 命令の選別

第 2 章に記述した命令のうち、3.1.1 節で不採用としたユニットにかかわる命令、および乗算、除算にかかわる命令は除外した。その上でプ
ログラムの実行に最低限必要な命令のみを使用するものとした。具体的には gcc や Spice が吐き出す機械語の統計より必要な命令を選別した。
また、この統計で一度除外された命令のうち、その後の検討で無いと不便と考えられる命令を若干追加した。GCC や Spice が吐き出す機械語の統計は表 3.1 のとおりである。[2]表 3.1

命令出現確率（％）

命令名 GCC SPICE
add
0
0
addi
0
0
addu
9
10
addiu
17
1
subu
0
1
and
1
0
andi
2
1
sll
5
5
srl
0
1
lui
2
6
lw
21
7
sw
12
2
lb
1
0
sb
1
0
beq
9
3
bne
8
2
jal
1
1
jr
1
1
slt
2
0
slti
1
0
sltu
1
0
sltiu
1
0

20

この表には命令出現確率が 0.5％を下回るものは載せてない。この表を元に命令の選別を行ったが、LB,SB(Load Byte, Store Byte)命令
に関しては、LW,SW(Load Word, Store Word)で代用のできるものであるから除外した。また、無いと困ると思われる命令、NOR,XOR,SUB 命
令等を付け加えて、必要な命令を決定した。採用した命令は以下のとお
りである。
●加算命令
●減算命令
●論理演算命令●大小比較命令●ビット列操作●メモリ命令●ジャンプ命令●条件分岐命令●その他

ADD 命令、ADDI 命令、ADDIU 命令、ADDU 命令
SUB 命令、SUBU 命令
AND 命令、ANDI 命令、OR 命令、ORI 命令
XOR 命令、XORI 命令、NOR 命令
SLT 命令、SLTI 命令、SLTU 命令、SLTUI 命令
SLL 命令、SRL 命令、LUI 命令
LW 命令、SW 命令
J 命令、JAL 命令、JR 命令
BEQ 命令、BNE 命令
NOP 命令3.1.3 全体の概要
以上の命令を処理する本設計での全体のブロック概要図は図 3.1 のとおりである。
プログラムカウンタ：プロセッサに順番に命令をフェッチする装置
命令メモリ：命令を格納しているメモリ
レジスタ：演算するデータを格納、読み出しする装置
ALU：データを演算、ビット操作する装置
データメモリ：データを蓄積するメモリアレイ

命令メモリ

レジスタ

ALU
プログラム
カウンタ

データメモリ

図3.1 全体ブロック図21

3.2 プログラムカウンタ設計
3.2.1 基本仕様設計

プロセッサに順番に命令をフェッチする装置としてプログラムカウン
タがある。プログラムカウンタは命令のアドレス、すなわち現在実行中の命令のアドレスを記憶しておく装置である。プログラムカウンタは現在保持している値を命令メモリに出力し、命令を読み出す。その後、次の命令のアドレスに自動的に更新し、次の命令を読み出す準備を整える。
その他 Jump 命令等で命令のアドレスを変更する時には、変更するアドレスをプログラムカウンタの値としてセットする。そのためプログラムカ
ウンタの入力線にはカウンタ更新アドレス、およびその制御線があり、クロックで同期して動作する。

Program
Counter

更新入力

アドレス出力制御線

図3.2

プログラムカウンタ概要

3.2.2 入出力線

プログラムカウンタの入出力線の概要は図 3.2 のとおりで、各機能およびその詳細は以下のとおりである。
入力線

Program Counter Input
Control Signal

22：Program Counter 更新入力
ALU2 よりのアドレス入力：Program Counter 制御信号
Operation Code

ALU Function CodeAll Zero 信号
出力線

Program Counter Output ：Instruction Memory へのアドレス出力。

32

Program
Counter

Address
Input

32
Instruction
Address

6
Operation
Code
6
ALU Function
Code
All Zero

図3.3

プログラムカウンタ概要

3.2.3 動作設計

本研究の Program Counter は、通常の１ずつ増加していく Program
Counter と異なり 4 ずつ増加するように設計した。理由はバイトという概念を使用できるようにしたので 32 ビットの命令長は 4 バイトを有することになったためである。そのため Instruction Memory のアドレス
は下位２ビットが 00 に固定されているので 4 ずつ加算する必要がある。
また、プログラムカウンタへの更新入力は、Jump 命令、Branch 命令、
All Zero 制御入力より判定して更新するように設計した。
表 3.2
命令
BEQ
BNE
J
JAL
JR

PC 更新を行う命令一覧

形式 Operation Code Fuction CodeI
0 0 0 1 0 0
I
0 0 0 1 0 1
J 0 0 0 0 1 0
J 0 0 0 0 1 1
R 0 0 0 0 0 0 0 0 1 0 0 0

図 3.2 の命令では、プログラムカウンタの外部入力による更新を行う
が、他の命令の時には通常更新をおこなう。どのような命令の場合も、
パイプライン中の 4 段目すなわちメモリアクセス時に更新を行うように

23

する。
Branch 命令の条件判定方法は以下のとおりである。
①Branch 命令の種類を判定する。
②BEQ 命令の時には All Zero 信号が１の場合にのみプログラムカウン
タを更新する。
③BNE 命令の時には ALL Zero 信号が０のときにのみプログラムカウン
タを更新する。

3.2.4 ソフトウェア作成上の注意点

本研究の Program Counter の設計では Jump 命令や Branch 命令での遅延スロットの制御を一切行わないため、これらの命令の直後に Jump
命令等の Program Counter を更新する命令が入る場合、結果が意図しないものになることがある。また、Branch 命令の直後も同様で、その直後の命令には、Branch 条件とはまったく無関係の命令若しくは NOP 命
令を重ねてパイプラインをストールさせなければならない。

3.3

ALU 基本仕様設計
本研究の ALU はデータ３入力、制御線入力、AllZero 出力、そしてデータ出力を備えている。また基本動作として論理演算（論理積、論理和、排他的論理和、否定論理和）、算術演算（加算、減算）、ビット列操作（シフト）が行えるように設計する。すべての命令はこの動作の組み合わせで動作するようにする。ALU に対するクロックタイミング制御は、すべてパイプラインレジスタ側の方で行う。本設計では、CPU レジスタと同
じく ALU 自身に命令解釈部を含み、命令を直接読み込んで動作するもの
とした。

24

データ入力

ALU

制御線

出力

図3.4

ALU概要

3.3.1 入出力線

ALU に対する入出力線の詳細は次のとおりである。
入力線

ALU Data Input,1 :レジスタよりのデータ入力
Source Register Data
ALU Data Input,2 :レジスタよりのデータ入力
Target Register Data
ALU Data Input,3 :符号拡張ユニットよりのデータ入力
Sign Extended Data
ALU Control Signal,1:ALU 制御用命令入力
Operation Code[31~26]
ALU Control Signal,2:ALU 制御用命令入力
ALU Function Code[5~0]
ALU Control Signal,3:シフト量入力(Shamt)
Instruction Code[10~6]

出力線

ALU Output Data

:ALU の演算結果
Execution Result

ALU Output Signal :ALU 演算結果のゼロ判定
All Zero25

All Zero
32
Source Register
Data

32

32

Target Register
Data

Excution
ResultALU

32
Sign Extended
Data
6
Operation
Code
6
ALU Function
Code

6

Shamt

図3.5

ALU入出力線図

3.3.2 動作設計

●加算機能
ALU における基本的な動作の一つが算術加算である。２つの入力デー
タをお互い加算しその結果を出力する。万が一、演算結果が０となる場
合には命令に応じて All Zero を出力する。また RISC の加算命令では桁上げ信号の処理を行わないので 32 ビットを超えて桁上げがある場合には無視される。
Operand1 + Operand2 → Execution Result●減算機能
加算機能のほかに算術命令で重要な働きをするのが減算機能である。
本来、２の補数を使う計算の場合、減算は必要ないが、RISC では減算は
主に大小判定、等号判定用として必要である。加算と同じく減算においても 32 ビットを超えて桁下がりがある場合は無視される。

26

Operand1 - Operand2 → Execution Result●論理積機能論理演算のなかでもっとも一般的なものが論理積である。オペランド
を数字としてではなくデータとして扱い、各ビットにおいて論理積をとったものを結果として出力する。
Operand1 AND Operand2 → Execution Result●論理和機能論理積と同じく多用される機能として論理和がある。動作は論理積と同様である。
Operand1 OR Opernad2 → Execution Result●否定論理和機能,排他的論理和機能
論理演算のなかで特に特殊な動きをするのがこれらの命令である。
Operand1 NOR Operand2 → Execution Result
Operand1 XOR Operand2 → Execution Result●ビット列操作機能
シフト命令で使用する。シフト量は ALU シフト数入力で決まる。動作についての詳細はシフト命令の項目で記述する。
以上の機能は命令入力に応じてオペランドを切り替え実行される。命令コードとの対応は表 3.3 のとおりである。
表 3.3 では記述の関係上、各機能および信号を以下のように略している。
算術加算機能→加算
算術減算機能 →減算
論理積機能
→AND
論理和機能
→OR
否定論理和機能 →NOR
排他的論理和 →XOR
Source Register Data
ビット列操作→Shift→RS
Target Register Data →RT
Sign Extended Data → SD27

表 3.3

ALU のデコード

命令 形式 Operation Code Fuction Code Operand1 Operand2 ALU機能
ADD
R 0 0 0 0 0 0 1 0 0 0 0 0
RS
RT
加算
ADDI
I
0 0 1 0 0 0
RSSD
加算
ADDU R 0 0 0 0 0 0 1 0 0 0 0 1
RSRT加算
ADDIU I
0 0 1 0 0 1
RS
SD
加算
SUB
R 0 0 0 0 0 0 1 0 0 0 1 0
RS
RT
減算
SUBU
R 0 0 0 0 0 0 1 0 0 0 1 1
RS
RT
減算
AND
R 0 0 0 0 0 0 1 0 0 1 0 0
RS
RT
AND
ANDI
I
0 0 1 1 0 0
RS
SD
AND
OR
R 0 0 0 0 0 0 1 0 0 1 0 1
RS
RT
OR
ORI
I
0 0 1 1 0 1
RS
SD
OR
SLL
R 0 0 0 0 0 0 0 0 0 0 0 0
RS
RT
Shift
SRL
R 0 0 0 0 0 0 0 0 0 0 1 0
RS
RT
Shift
RT
NOR
R 0 0 0 0 0 0 1 0 0 1 1 1
RS
NOR
RT
XOR
R 0 0 0 0 0 0 1 0 0 1 1 0
RS
XOR
SD
XORI
I
0 0 1 1 1 0
RS
XOR
RT
NOP
R 0 0 0 0 0 0 0 0 0 0 0 0
RS
Shift
LUI
I
0 0 1 1 1 1
RS
SD
Shift
LW
I
1 0 0 0 1 1
RS
SD
加算
SW
I
1 0 1 0 1 1
RS
SD
加算
BEQ
I
0 0 0 1 0 0
RS
RT
減算
BNE
I
0 0 0 1 0 1
RS
RT
減算
J
J 0 0 0 0 1 0------------JAL
J 0 0 0 0 1 1------------JR
R 0 0 0 0 0 0 0 0 1 0 0 0
RS
RT
Shift
SLT
R 0 0 0 0 0 0 1 0 1 0 1 0
RS
RT
減算
SLTI
I
0 0 1 0 1 0
RS
SD
減算
SLTU
R 0 0 0 0 0 0 1 0 1 0 1 1
RS
RT
減算
SLTIU
I
0 0 1 0 1 1
RSSD
減算
デコードの表 3.3 および各命令動作より次のことがいえる。
●Operation Code が全て０である場合、命令は R 形式である。
●メモリに関する命令は Operation Code の最上位ビットが１である。
●Operation Code の 3 ビット目が 1 である場合には Jump 命令、分岐命令以外の標準の I 形式の命令である。
デコードの手順①

もし、Operation Code=All Zero ならば R 形式命令なので

28

Operand1=RS,②

Operand2=RT とする。

①の条件を満たす場合にはその演算形式を判定する。

ALU Function Code[5][2][1]=100 ならば ALU は加算を行う。
ただし ALU Function Code[0]=1 ならば AllZero 出力をしない。
ALU Function Code[5][2][1]=101 ならば ALU は減算を行う。
ただし ALU Function Code[3]=1 ならば大小比較命令を行う。
また、ALU Function Code[0]=1 ならば AllZero 出力をしない。
ALU Function Code[5][2][1][0]=1100 なら ALU は AND を行う。
ALU Function Code[5][2][1][0]=1101 なら ALU は OR を行う。
ALU Function Code[5][2][1][0]=1110 なら ALU は NOR を行う。
ALU Function Code[5][2][1][0]=1111 なら ALU は XOR を行う。
ALU Function Code[5][2][1]=000 ならば ALU は Shift を行う。
ただし ALU Function Code[3]=0 の時には右シフトを、1 のときには左シフトを行う。
③ ①を満たさない場合には Operation Code[5]=1 ならばメモリ命令
として、ALU は加算を行う。
④ ③を満たさない場合 Operation Code[3]=1 ならば I 形式命令な
ので、Operand1=RS, Operand2=SD とする。
⑤④の条件を満たす場合その演算形式を判定する。

Operation Code[2][1]=00 ならば ALU は加算を行う。
ただし、Operation Code[0]=1 ならば AllZero を出力しない。
Operation Code[2~0]=100 ならば ALU は AND を行う。
Operation Code[2~0]=101 ならば ALU は OR を行う。
Operation Code[2~0]=110 ならば ALU は XOR を行う。
Operation Code[2~0]=111 ならば ALU は LUI 命令を行う。
Operation Code[2][1]=01 ならば ALU は減算を行う。
ただし Operation Code[0]=1 の時には AllZero を出力しない。
⑥④を満たさない場合

29

Operation Code[2~0]=100 ならば ALU は BEQ 命令として減算を行う。
Operation Code[2~0]=101 ならば ALU は減算を行い、Allzero には
通常の出力を反転させたものを出力する。
Operation Code[2][1]=01 ならば Jump 命令なので ALU は動作しない。

3.4 CPU レジスタ仕様設計
3.4.1 仕様

本研究で設計したプロセッサには、32 個各 32 ビットの汎用レジスタを内蔵している。レジスタ番号 0 および 31 は特殊レジスタとして予約され、レジスタ０は NOP 命令および０を必要とする演算のためにハードウ
ェア的に０に固定されている。レジスタ 31 は JAL（Jump And Link）
命令用の Program Counter 値格納用である。レジスタ 1〜30 まではユーザがプログラムで自由に使用可能なレジスタである。また、レジスタ
は複数入出力線を持つマルチポートメモリである。
本設計では CPU レジスタの部分に命令解釈部を設け、命令コードを直接読み込んでそれを解読し、動作するものとした。

特殊レジスタ

汎用レジスタ特殊レジスタ-

図3.6

ＣPUレジスタ

30

Register 00

Register
01〜30

Register 31

3.4.2 入出力線

すべての命令に対応するために CPU レジスタの入出力線は次のように
設定した。
入力線

R 形式用

Source Register Address 線 5 ビット
Target Register Address 線 5 ビット
Destination Register Address 線 5 ビット
Execution Result 線 32 ビット
Program Counter 線 32 ビット

I 形式用

周回 Target Register Address 線 5 ビット
Load Data 線 32 ビット
Operation Code 線 6 ビット
Source Register Data 線 32 ビット
Target Register Data 線 32 ビット

制御線
出力線

Source Register Address, Target Register Address,
Destination Address 線は命令コードの一部分である。
Source Register Address=命令コードの 25 ビット目〜21 ビット目。
Target Register Address=命令コードの 20 ビット目〜16 ビット目。
Destination Register Address=命令コードの 15〜10 ビット目。
周回 Target Register Address は I 形式命令において Destination
Address となるものであり、パイプラインを周回させてきた Target
Register Address である。データ入力線の Load Data, Execution
Result, Program Counter 線はそれぞれデーターメモリからの出力
データ、ALU 演算結果、プログラムカウンタの値となる。

31

5Source Register
Address
532

Target Register
Address

Source Register
Data
5

Destination Register
Address
5
周回Target Register
Address

Register
32

ProgramCounte
r
32

32

Load
Data

Target Register
Data
32

Execution
Result6Operation
Code

図3.7

レジスタ概要図

3.4.3 動作ま ず 、 Source Register Address お よ び Target Register
Address で指示されたレジスタ番号のデータを読み出し、それを各々
Source Register Data, Target Register Data とする。半クロ
ック遅れで命令をデコードし、それをもとに書込み作業を行う。
デコードの対応表は次のとおりである。なお、周回 Target Register
Data は周回 TR、Destination Register は RD、Execution Result
は ExecResult とする。

32

表 3.4
命令
ADD
ADDI
ADDU
ADDIU
SUB
SUBU
AND
ANDI
OR
ORI
NOR
XOR
XORI
NOP
SLL
SRL
LUI
LW
JAL
SLT
SLTI
SLTU
SLTIU

レジスタデコード

形式 OperationCode 保存先アドレス 保存データ
R 0 0 0 0 0 0
RD
ExecResultI
0 0 1 0 0 0
周回RT
ExecResult
R 0 0 0 0 0 0
RD
ExecResultI
0 0 1 0 0 1
周回RT
ExecResult
R 0 0 0 0 0 0
RD
ExecResult
R 0 0 0 0 0 0
RD
ExecResult
R 0 0 0 0 0 0
RD
ExecResultI
0 0 1 1 0 0
周回RT
ExecResult
R 0 0 0 0 0 0
RD
ExecResultI
0 0 1 1 0 1
周回RT
ExecResult
R 0 0 0 0 0 0
RD
ExecResult
R 0 0 0 0 0 0
RD
ExecResultI
0 0 1 1 1 0
周回RT
ExecResult
R 0 0 0 0 0 0
RD
ExecResult
R 0 0 0 0 0 0
RD
ExecResult
R 0 0 0 0 0 0
RD
ExecResultI
0 0 1 1 1 1
周回RT
ExecResultI
1 0 0 0 1 1
周回RT
LoadData
J 0 0 0 0 1 1 レジスタ３１
PC
R 0 0 0 0 0 0
RD
ExecResultI
0 0 1 0 1 0
周回RT
ExecResult
R 0 0 0 0 0 0
RD
ExecResultI
0 0 1 0 1 1
周回RT
ExecResult

表 3.4 より、デコードは次の手順で行う。
①Operation Code=AllZero すなわち
(Operation Code)XOR = 1 ならば
Input Address = RD , Input Data = Exec Result②Operation Code[3]= 1 ならば
Input Address= 周回 RT , Input Data= Exec Result③Operation Code[5]= 1 ならば
Input Address= 周回 RT , Input Data= Load Data
④すべてに該当しないなら、
Input Address= Register[31] , Input Data = PC

33

3.5 その他機能部の設計
3.5.1 命令メモリ（Instruction

Memory）の設計

本研究ではプロセッサの命令メモリを 32 ビット幅 64 行のメモリとした。ハードウェア量としては非常に少ないが、シミュレーションおよび動作検証を行う上では十分だと判断したからである。本来はメモリとして外部から書き換えできるように設計するべきだが、本設計ではあらか
じめ命令テーブルを作っておく方式とした。入力線としては 32 ビットの命令アドレス線、出力線としては 32 ビットの命令データ線のみで、クロックによる制御は行わない。
32
Instruction
Address

図3.8

Instruction
Memory32
Instruction
Address

命令メモリ入出力線

動作はきわめて簡単で、入力アドレスを元に対象となるデータを出力するだけである。

3.5.2 データーメモリ（Data Memory）の設計

データーメモリは命令メモリと違って命令デコーダを内蔵し、データーメモリを必要とする命令の場合のみに書込み動作を行う。データーメ
モリを必要とする命令は Load 命令、および Store 命令のみである。書込みを行う命令は Operation Code を解読して書込み動作を行う。入力
線ではデーターメモリ読み出し用アドレス、データーメモリ書込み用データ、出力線は読み出しデータである。なお、メモリアクセスは 1 クロックに付き１度しか動作しないので Register のようにマルチポートメ
モリとする必要性はない。さらに命令読み出しは、書込み命令以外の全ての命令で読み出しを行ったとしても、読み出したデータの行き先はRegister となり、Register で適切に処理されるため問題はないが、

34

32 ビット分のアドレスのメモリを積み込むわけではないので誤動作を避けるために Load 命令のときだけメモリ読み出しを行うようする。Load
命 令 の Operation Code= (100011),Store 命 令 の Operation
Code=(101011) であることから メモリアクセス動作は Operation
Code を解読して行う。

32

Data
Memory

Data
Input

32
Data
Output32
Address Input
6Operation
Code

図3.9

データメモリ入出力線

3.5.3 補助 ALU（ALU2）の設計

Branch 命令、JAL 命令では ALU がすでに使用されているので同時にアドレス計算をできない。そのためアドレス計算専用の ALU2 を用意している。ALU2 では４つのデータ入力線、２つの制御線、１つの出力線を備
え、各命令に応じて入力線を選びアドレスを計算する。各入力線は以下のとおりである。
入力線

ALU2 Input Data,1：Pipeline Register を通過してきた Program Counter のデータ
ALU2 Input Data,2：Source Register Data
ALU2 Input Data,3：Sign Extended Data
ALU2 Input Data,4：Instruction Code[25~0]
出力線 ALU2 Output Data：Program Counter Address Input
ALU2 を使用する命令は Branch 命令、JAL 命令のほかに、JR 命令、
Jump 命令 があげられる。各命令の Operation Code および ALU
Function Code は表 3.5 のとおりである。なお各端子の記述は省略形にしている。

35

表 3.5

命令 形式
BEQ
I
BNE
I
J
J
JAL
J
JR
R

ALU2 デコード表

Operation Code Function Code Operand1 Operand2
0 0 0 1 0 0----PCSD
0 0 0 1 0 1----PCSD----0 0 0 0 1 0
PC
Inst[25-0]----0 0 0 0 1 1
PC
Inst[25-0]
0 0 0 0 0 0 0 0 1 0 0 0
RS
-----

Program
Counter32

Sign Extended
Data

32

Instruction Code[250]32

Source Register
Data

32

ALU2

32

PC Input
Address

OperationCode
ALU Function
Code

図3.10

補助ALU入出力線

動作としては、まず Operation Code および ALU Function Codeが一致することを確認する。次にその命令動作に移る。命令自身の詳細は後述する。表 3.5 の Operand2 に関しては、入力が無いものとして扱うため内部では０として処理するものとする。
●BEQ 命令の場合
SD の入力値 の下 位 ２ ビット に０を結 合する。結合後 、Program
Counter の値に４を加えたものを加算する。加算結果が 32 ビットを超えてしまうので、下位から 32 ビット分残し上位ビットを切り捨てる。

36

●BNE 命令の場合
BEQ 命令と同じである。
●J 命令の場合
Program Counter の 31 ビット目〜28 ビット目と命令コードの 25
ビット目〜０ビット目、そして 0 を 2 ビット分全て結合する。結合した
結果が出力である。
●JAL 命令の場合
J 命令と同じである。
●JR 命令の場合
RS で読み出されたデータをそのまま出力とする。

3.5.4 符号拡張ユニット（Sign Extend Unit）の設計

Immediate 形式の命令の場合、ALU が 32 ビットなのであらかじめ符
号拡張が必要である。符号拡張についての詳細は第 2 章で述べたとおりである。この符号拡張ユニットでは命令ごとにその拡張方法を判断し、ゼロ拡張か符号拡張かのいずれかを行う。符号拡張ユニットを使用する
命令は表 3.6 のとおりである。
表 3.6

拡張形式命令対応表

命令 形式 Operation Code Operand1
ADDII
0 0 1 0 0 0 符号拡張
ADDIU I
0 0 1 0 0 1 ゼロ拡張
ANDII
0 0 1 1 0 0 ゼロ拡張
ORII
0 0 1 1 0 1 ゼロ拡張
XORI
I
0 0 1 1 1 0 ゼロ拡張
LUI
I
0 0 1 1 1 1 ゼロ拡張
LWI
1 0 0 0 1 1 符号拡張SWI
1 0 1 0 1 1 符号拡張
BEQ
I
0 0 0 1 0 0 符号拡張
BNE
I
0 0 0 1 0 1 符号拡張
SLTI
I
0 0 1 0 1 0 符号拡張
SLTIU I
0 0 1 0 1 1 符号拡張
ゼロ拡張を必要とする演算は符号なし（ADDIU のみ）の通常演算と論37理演算である。その他、ビット操作命令の一つである LUI 命令も同様である。符号拡張ユニットの入力線は 16 ビットの Immediate および６ビットの制御線、出力は拡張された Immediate の 32 ビットである。
Immediate

OperationCod
e

図3.11

16

符号拡張ユニット

32 Sign Extended
Data

6

符号拡張ユニット入出力線図

3.5.5 パイプラインレジスタ（PR0,PR1,PR2）の設計

本設計のプロセッサの各ユニットにはクロックによって制御するものも若干あるが、大半のユニットではクロックによる制御を行わない。また、パイプライン方式を採用することで、回路上にまったく別の命令を次々にフェッチすることになるので、パイプラインを構成する各ユニッ
トのタイミング制御を適切に行わなければ命令が正しく動作しない。そのため、パイプラインレジスタというレジスタをユニット毎（正確には１パイプラインステージ毎）に設置する必要性がある。パイプラインレ
ジスタは特にこれといった動作はしない。ただ単に入力したデータを一時的に格納し、次のクロックで出力するものである。パイプラインレジ
スタは基本的に D-FF で構成される。また、回路とパイプラインステージの都合上パイプラインレジスタを３つに分割する。
まず第１パイプラインレジスタ（PR0）ではパイプラインステージのフェッチ、デコード（レジスタリード）間でのデータの受け渡し、そのあとのメモリアクセス、ライトバック（レジスタライト）間での動作を同時に行う。命令コードを入力されると、これをソースレジスタアドレス、
ターゲットレジスタアドレス、デスティネーションレジスタアドレス、
Immediate データ、Operation Code、ALU Function Code、Jump
Address の各々に分割する。このレジスタに対しての入出力線は次のとおりである。

38

Program Counter
Data

Instruction
Code

32

32

32

Program Counter
Data

5

Source Register
Address

5

Target Register
Address

5

Destination Register
Address

16

Immediat
e

26

Jump
Address

6

Operation
Code

6

ALU Function
Code

PR1
5

Shamt

周回Program Counter
data

32

32

周回Program Counterdata

周回Target Register
Address

5

5

周回Target Register
Address

周回Destination Register
Address

5

5

周回Destination Register
Address

Load
Data

32

32

Load
Data

Execution
Result32

32

Execution
ResultOperation
Code

6

6

周回Operation
Code

図3.12

第1パイプラインレジスタ入出力線図

Source Register Address”5=Instruction Code[25~21]
Target Register Address”5=Instruction Code[20~16]
Destination Register Address”5=Instruction Code[15~11]
Immediate”16=Instruction Code[15~0]
Jump Address”26=Instruction Code[25~0]
Operation Code”6=Instruction Code[31~26]
ALU Function Code”6=Instruction Code[5~0]39Shamt”5=Instruction Code[10~6]
次に第 2 パイプラインレジスタは、第１パイプラインレジスタと異なり単純に入力されたデータを次のクロックで出力するだけでり、第 1 パ
イプラインレジスタよりも信号が少ない。ただし、動作的にはまったく
変 わ り 無 い が こ こ で Destination Register Address を 周 回
Destination Register Address に、Target Register Address
を周回 Target Register Address に変更する。入出力信号線の概要
は図 3.13 のとおりである。

Target Register
Address

5

5

周回Target Register
Address

Destination Register
Address

5

5

周回Destination Register
Address

Program Counter
Data

32

32

Program Counter
Data

Source Register
Data

32

32

Source Register
Data

Target Register
Data

32

32

Target Register
Data

Shamt

PR2

5

5

Shamt

Jump
Address

26

26

Jump
Address

Sign Extend
Data

32

32

Sign Extend
Data

Operation
Code

6

6

OperationCode

ALU Function
Code

6

6

ALU Function
Code

図3.13

第2パイプラインレジスタ入出力線図

第 3 パイプラインレジスタは第 2 パイプラインレジスタと同様の動作をする。ただし、Program Counter Data が周回 Program Counter
Data となる。第 3 パイプラインレジスタの入出力線は図 3.14 のとおり
である。

40

周回Target Register
Address

5

5

周回Target Register
Address

周回Destination Register
Address

5

5

周回Destination Register
Address32

32

Address

AllZeroAddress

AllZeroExecution
Result32

Target Register
Data

PR3

32

Execution
Result32

32

Target Register
Data

ALU Function
Code

6

6

ALU Function
Code

Operation
Code

6

6

Operation
Code

図3.14

第3パイプラインレジスタ入出力線図

3.6 データーパス設計
3.6.1 R 形式命令用データーパス設計

R 形式命令の処理手順は命令フェッチ→デコード→演算→レジスタ格納である。この順番で図 3.15 のようにデータパスをつなげば命令処理できる。なお各ブロック間にパイプラインレジスタを挟み、タイミングを取っている。またパイプラインは５段なので R 形式命令の場合にはメモ
リアクセスフェーズでは動作しないようにした。

41

5
RD
ADD
5
RS
5
RT
PC
5

32

32

32

32

Register

32
PR１

32
ALU

PR１

PR１

Instruction
Memory
6

6

6

6

6

6

6

6

OP CODE6632 32
Function

図 3.15R 形式データパス

3.6.2 I 形式命令用データーパス設計

I 形式命令には分岐命令やメモリアクセス命令が含まれる。そのため単純な演算のみのデーターパスだけではなくこれら命令を処理するためのデーターパスが必要になる。このためデーターパスは、上記の R 形式データーパスに分岐命令、メモリアクセス命令の処理系を付け加えたものとなる。また、メモリアクセス命令および、Immediate を扱うので、伴う機能部（データメモリ、符号拡張ユニット、補助 ALU）が必要になる。
なお、I 形式ではメモリアクセス命令においてパイプラインのメモリアクセスフェーズにメモリアクセスを行うが、他の命令ではメモリアクセスを行わないので、R 形式と同じようにここでは動作しないように設計した。

42

32

5
RT

32
32

ADD
32

32
SUB
ALU

5
RS
32

5
RT
PC

5

32

32

32

32

Register

DataMemory

32
PR１

ALU

PR１

32

32
PR１
32

Instruction
Memory

32

6
32

16

32

32

Immediate
ビット拡張ユニット
6

6

6
6

6

6

6

6

6

6

OP CODE6632 32
Function

図 3.16I 形式データーパス

3.6.3 J 形式命令用データーパス設計

本設計での J 形式命令は Jump 命令、Jump And Link(JAL)命令のみ
で、これらを処理するためのデーターパスを設計した。J 形式命令ではオ
ペランドは 26 ビットのアドレスのみなので、それを I 形式の Branch
命令と同じように付録の命令処理に従って、補助 ALU で処理する。また、
ALU やデータメモリ、および符号拡張ユニットは使用しない。他の形式とは異なり、JAL 命令では保存先アドレスが命令コードの中に含まれていないので、専用のアドレスレジスタ（レジスタ 31）を使用する。設計
したデーターパスは図 3.17 の通りである。

43

32

32
32

ADD
32

26

32
SUB
ALU

PC

Register

32
PR１

PR１

PR１

Instruction
Memory
6

6

6

6

6

OP CODE6632 32
Function

図 3.17J 形式データーパス

3.6.4 全体のデータパス

全体のデーターパスはすべての命令形式（R 形式、I 形式、J 形式）のデーターパスを結合したものである。結合し、完成したデータパスは付録に添付するとおりである。

44

第４章 VHDL 記述
第 3 章での設計を元に VHDL による記述およびシミュレーションを行った。VHDL の各モジュールは図 4.1 のように階層構成とした。各モジュールは第３章で述べた各機
能ブロックに対応する。VHDL エディタは Xilinx 社 WebPackISE、シミュレータはModelSim XE を使用した。[3][4][5]Data Memory

ALU

ALU2

CPU̲Register
CPU.Vhd
Program̲Counter

PipeLine Register

Sign̲Extend̲Unit

図4.1

Instruction
Memory4.1 各機能ブロックの記述

4.1.1

ALU の記述library IEEE;

45

VHDL階層use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity ALU is
Port ( Source_Register_Data : in std_logic_vector(31 downto 0);
Target_Register_Data : in std_logic_vector(31 downto 0);
Sign_Extended_Data : in std_logic_vector(31 downto 0);
Operation_Code : in std_logic_vector(5 downto 0);
ALU_Function_Code : in std_logic_vector(5 downto 0);
Shamt : in std_logic_vector(4 downto 0);
AllZero : out std_logic;
Execution_Result : out std_logic_vector(31 downto 0));end ALU;
architecture TIKUWA of ALU is
begin
process(Operation_Code,ALU_Function_Code,Source_Register_Data,Target_Reg
ister_Data,Sign_Extended_Data,Shamt)
variable temp: std_logic_vector(32 downto 0);
variable zero: std_logic_vector(32 downto 0);
begin
zero := "000000000000000000000000000000000";-- R Type Instruction Process----------------------------------------------------------------------------case Operation_Code iswhen "000000" =>case ALU_Function_Code is-- ADD Arithmetical Instruction Process-------------------------------------------------------------------------when "100000" =>temp := (Source_Register_Data(31) & Source_Register_Data) +(Target_Register_Data(31) & Target_Register_Data);
if (temp(32)=temp(31)) then
else

46

temp := zero;end if;-- ADDU Arithmetical Instruction Process-------------------------------------------------------------------------when "100001" =>temp := ("0" & Source_Register_Data) + ("0" & Target_Register_Data);-- SUB Arithmetical Instruction Process-------------------------------------------------------------------------when "100010" =>temp := (Source_Register_Data(31) & Source_Register_Data) (Target_Register_Data(31) & Target_Register_Data);
if (temp(32)=temp(31)) thenelsetemp := zero;end if;-- SUBU Arithmetical Instruction Process-------------------------------------------------------------------------when "100011" =>temp := ("0" & Source_Register_Data) - ("0" & Target_Register_Data);-- AND Logical Instruction Process-------------------------------------------------------------------------when "100100" =>temp := ("0"&Source_Register_Data) AND ("0"&Target_Register_Data);-- OR Logical Instruction Process-------------------------------------------------------------------------when "100101" =>temp := ("0"&Source_Register_Data) OR ("0"&Target_Register_Data);-- NOR Logical Instruction Process-------------------------------------------------------------------------when "100111" =>temp := ("0"&Source_Register_Data) NOR ("0"&Target_Register_Data);-- XOR Logical Instruction Process-------------------------------------------------------------------------when "100110" =>temp := ("0"&Source_Register_Data) XOR ("0"&Target_Register_Data);-- SLL,NOP,JR Logical Instruction process47

-------------------------------------------------------------------------when "000000" | "001000"=>
temp := "0" & SHL(Source_Register_Data,shamt);-- SRL Logical Instruction Process-------------------------------------------------------------------------when "000010" =>temp := "0" & SHR(Source_Register_Data,shamt);-- SLT Logical Instruction Process-------------------------------------------------------------------------when "101010" =>if (Source_Register_Data < Target_Register_Data) thentemp := zero(31 downto 0) & "1";else
temp := zero;end if;-- SLTU Logical Instruction Process-------------------------------------------------------------------------when "101011" =>if ("0" & Source_Register_Data < "0" & Target_Register_Data) thentemp := zero(31 downto 0) & "1";else
temp := zero;end if;when others =>temp := zero;end case;-- I type Instruction-- ADDI Arithmetical Instruction Process----------------------------------------------------------------------------when "001000" =>temp := (Source_Register_Data(31) & Source_Register_Data) +(Sign_Extended_Data(31) & Sign_Extended_Data);
if (temp(32)=temp(31)) thenelsetemp := zero;end if;48

-- ADDIU Arithmetic Instruction Process----------------------------------------------------------------------------when "001001" =>temp := ("0" & Source_Register_Data) + ("0" & Sign_Extended_Data);-- AND Logical Instruction Process-------------------------------------------------------------------------when "001100" =>temp := ("0"&Source_Register_Data) AND ("0"&Sign_Extended_Data);-- OR Logical Instruction Process-------------------------------------------------------------------------when "001101" =>temp := ("0"&Source_Register_Data) OR ("0"&Sign_Extended_Data);-- XORI Logical Instruction Process-------------------------------------------------------------------------when "001110" =>temp := ("0"&Source_Register_Data) XOR ("0"&Sign_Extended_Data);-- LUI Logical Instruction Process-------------------------------------------------------------------------when "001111" =>temp := "0" & SHL(Sign_Extended_Data,"10000");-- LW,SW Logical Instruction Process--------------------------------------------------------------------------when "100011" | "101011" =>temp := "0" & (Source_Register_Data + Sign_Extended_Data);
temp(1 downto 0) := "00";-- BEQ,BNE Logical Instruction Process-------------------------------------------------------------------------when "000100" | "000101" =>temp := "0" & (Source_Register_Data - Target_Register_Data);-- SLTI Logical Instruction Process-------------------------------------------------------------------------when "001010" =>if (Source_Register_Data < Sign_Extended_Data) thentemp := zero(31 downto 0) & "1";
else

49

temp := zero;end if;-- SLTIU Logical Instruction Process-------------------------------------------------------------------------when "001011" =>if ("0" & Source_Register_Data < "0" & Sign_Extended_Data) thentemp := zero(31 downto 0) & "1";else
temp := zero;end if;when others =>temp := zero;end case;-- ALL ZERO Detection----------------------------------------------------------------------------if(temp="0") then
AllZero <='1';
else
AllZero <='0';
end if;-- Result Output----------------------------------------------------------------------------Execution_Result <= temp (31 downto 0);
end Process;end TIKUWA;

4.1.2 CPU レジスタの記述
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity cpu_register isPort ( Source_Register_Address : in std_logic_vector(4 downto 0);50Target_Register_Address : in std_logic_vector(4 downto 0);
Destination_Register_Address : in std_logic_vector(4 downto 0);
Cyclic_Target_Register_Address : in std_logic_vector(4 downto 0);
Program_Counter : in std_logic_vector(31 downto 0);
Load_Data : in std_logic_vector(31 downto 0);
Execution_Result : in std_logic_vector(31 downto 0);
Operation_Code : in std_logic_vector(5 downto 0);
Source_Register_Data : out std_logic_vector(31 downto 0);
Target_Register_Data : out std_logic_vector(31 downto 0);
Clock : in std_logic);end cpu_register;architecture TIKUWA of cpu_register istype Register_Array is array (0 to 31) of std_logic_vector(31 downto 0);
signal Reg: Register_Array;begin
t1:process(Operation_Code,Source_Register_Address,Target_Register_Address,Clock)begin
Reg(0) <= "00000000000000000000000000000000";
Source_Register_Data <= Reg(CONV_INTEGER(Source_Register_Address));
Target_Register_Data <= Reg(CONV_INTEGER(Target_Register_Address));
end process;t2: process (Clock)begin
Reg(0) <= "00000000000000000000000000000000";if (Clock'event and Clock='0') thencase Operation_Code iswhen "000000" =>if (Destination_Register_Address="00000") thenReg(0) <= "00000000000000000000000000000000";else
Reg(CONV_INTEGER(Destination_Register_Address))<=
Execution_Result;51

end if;when "001000" | "001001" | "001100" | "001101" | "001110" | "001111" |"001010" | "001011" =>if (Cyclic_Target_Register_Address="00000") thenReg(0) <= "00000000000000000000000000000000";else
Reg(CONV_INTEGER(Cyclic_Target_Register_Address))<=
Execution_Result;end if;when "100011" =>if (Cyclic_Target_Register_Address="00000") thenReg(0) <= "00000000000000000000000000000000";else
Reg(CONV_INTEGER(Cyclic_Target_Register_Address)) <= Load_Data;
end if;when "000011" =>Reg(31) <= Program_Counter;when others =>Reg(0) <= "00000000000000000000000000000000";
end case;end if;end process;end TIKUWA;

4.1.3 補助 ALU の記述
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity ALU2 isPort ( Program_Counter : in std_logic_vector(31 downto 0);
Sign_Extended_Data : in std_logic_vector(31 downto 0);
Address_Input : in std_logic_vector(25 downto 0);52Source_Register_Data : in std_logic_vector(31 downto 0);
Operation_Code : in std_logic_vector(5 downto 0);
ALU_Function_Code : in std_logic_vector(5 downto 0);
PC_Output : out std_logic_vector(31 downto 0);
Link_Register_Data : out std_logic_vector(31 downto 0));end ALU2;
architecture TIKUWA of ALU2 is
begin
process (Operation_Code,Alu_Function_Code,Program_Counter)variable temp1,temp2: std_logic_vector(31 downto 0);
begincase Operation_Code is-----------Branch Instruction ----------------------------------------when "000100" | "000101" =>temp1 := SHL(Sign_Extended_Data,"10");
temp2 := Program_Counter + "100";
PC_Output <= temp1 + temp2;-----------Jump Instruction ------------------------------------------when "000010" =>PC_Output <= Program_Counter(31 downto 28) & Address_Input &"00";-----------Jump And Link Instruction ---------------------------------when "000011" =>PC_Output <= Program_Counter(31 downto 28) & Address_Input &"00";
Link_Register_Data <= Program_Counter + "1000";-----------Jump Register Operation -----------------------------------when "000000" =>if (ALU_Function_Code="001000") then
PC_Output <= Source_Register_Data ;end if;when others =>PC_Output <= "00000000000000000000000000000000";
end case;end process;53

end TIKUWA;

4.1.4 プログラムカウンタの記述
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity PC isPort ( Program_Counter_Input : in std_logic_vector(31 downto 0);
Operation_Code : in std_logic_vector(5 downto 0);
ALU_Function_Code : in std_logic_vector(5 downto 0);
AllZero : in std_logic;
Program_Counter_Output : out std_logic_vector(31 downto 0);
Clock : in std_logic;
Reset : in std_logic);end PC;architecture TIKUWA of PC issignal count: std_logic_vector(31 downto 0);
begin
Program_Counter_Output <= count;process (Clock,Reset) begin
if(Reset='1') thencount <= "00000000000000000000000000000000";
else if(Clock'event and Clock='1') thencase Operation_Code iswhen "000100" =>if (AllZero='1') thencount <= Program_Counter_Input;
else
count <= count + "100";end if;54

when "000101" =>if (AllZero='0') thencount <= Program_Counter_Input;
else
count <= count + "100";end if;when "000010" | "000011"=>count <= Program_Counter_Input;
when "000000" =>if (ALU_Function_Code="001000") thencount <= Program_Counter_Input;
else
count <= count + "100";end if;when others =>count <= count + "100";end case;end if;end if;end process;end TIKUWA;

4.1.5 データメモリの記述
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity DataMemory isPort ( Target_Register_Data : in std_logic_vector(31 downto 0);
Execution_Result : in std_logic_vector(31 downto 0);
Operation_Code : in std_logic_vector(5 downto 0);
Load_Data : out std_logic_vector(31 downto 0));end DataMemory;55

architecture TIKUWA of DataMemory istype DATA_Memory_Array is array (0 to 31) of std_logic_vector(31 downto 0);
signal Mem: Data_Memory_Array;
begin
process (Operation_Code,Target_Register_Data,Execution_Result)
begincase Operation_Code iswhen "100011" =>Load_Data <= Mem(CONV_INTEGER('0' & Execution_Result(6 downto 2)));
when "101011" =>Mem(CONV_INTEGER('0' & Execution_Result(6 downto 2)))<= Target_Register_Data;
when others =>end case;end process;end TIKUWA;

4.1.6 符号拡張ユニットの記述
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity Sign_Extend_Unit isPort ( Immediate : in std_logic_vector(15 downto 0);
Operation_Code : in std_logic_vector(5 downto 0);
Sign_Extended_Data : out std_logic_vector(31 downto 0));end Sign_Extend_Unit;architecture TIKUWA of Sign_Extend_Unit is
begin
process (Immediate,Operation_Code)
begin

56

case Operation_Code iswhen "001000" | "100011" | "101011" | "000100" | "000101" | "001010" |"001011" =>Sign_Extended_Data <= Immediate(15) & Immediate(15) &Immediate(15)&Immediate(15)&Immediate(15)&Immediate(15)&Immediate(15)&Immediate(15)&Immediate(15)&Immediate(15)&Immediate(15)&Immediate(15)&Immediate(15)&Immediate(15)&Immediate(15) & Immediate(15) & Immediate;when "001001" | "001100" | "001101" | "001110" | "001111" =>Sign_Extended_Data <= "0000000000000000" & Immediate;when others =>Sign_Extended_Data <= "00000000000000000000000000000000";
end case;end process;end TIKUWA;

4.1.7 第 1 パイプラインレジスタの記述
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity PR0 is
Port ( Program_Counter_Data_in : in std_logic_vector(31 downto 0);
Instruction_Code_in : in std_logic_vector(31 downto 0);
Cyclic_Program_Counter_Data_in : in std_logic_vector(31 downto 0);
Cyclic_Target_Register_Address_in : in std_logic_vector(4 downto 0);
Cyclic_Destination_Register_Address_in : in std_logic_vector(4 downto 0);
Load_Data_in : in std_logic_vector(31 downto 0);
Execution_Result_in : in std_logic_vector(31 downto 0);
Operation_Code_in : in std_logic_vector(5 downto 0);
Program_Counter_Data_out : out std_logic_vector(31 downto 0);
Sourcd_Register_Address_out : out std_logic_vector(4 downto 0);57

Target_Register_Address_out : out std_logic_vector(4 downto 0);
Destination_Register_Address_out : out std_logic_vector(4 downto 0);
Immediate_out : out std_logic_vector(15 downto 0);
Jump_Address_out : out std_logic_vector(25 downto 0);
Operation_Code_out : out std_logic_vector(5 downto 0);
ALU_Function_Code : out std_logic_vector(5 downto 0);
Shamt_out : out std_logic_vector(4 downto 0);
Cyclic_Program_Counter_Data_out : out std_logic_vector(31 downto 0);
Cyclic_Target_Register_Address_out : out std_logic_vector(4 downto 0);
Cyclic_Destination_Register_Address_out : out std_logic_vector(4 downto 0);
Load_Data_out : out std_logic_vector(31 downto 0);
Execution_Result_out : out std_logic_vector(31 downto 0);
Cyclic_Operation_Code : out std_logic_vector(5 downto 0);
Clock : in std_logic);end PR0;
architecture TIKUWA of PR0 is
begin
process(Clock)begin
if(Clock'event and Clock = '1') thenProgram_Counter_Data_out <= Program_Counter_Data_in after 100 ps;
Sourcd_Register_Address_out <= Instruction_Code_in(25 downto 21) after 100
ps;Target_Register_Address_out <= Instruction_Code_in(20 downto 16) after
100 ps;Destination_Register_Address_out <= Instruction_Code_in(15 downto 11)
after 100 ps;
Immediate_out <= Instruction_Code_in(15 downto 0) after 100 ps;
Jump_Address_out <= Instruction_Code_in(25 downto 0) after 100 ps;
Operation_Code_out <= Instruction_Code_in(31 downto 26) after 100 ps;
ALU_Function_Code <= Instruction_Code_in(5 downto 0) after 100 ps;
Shamt_out <= Instruction_Code_in(10 downto 6) after 100 ps;
Cyclic_Program_Counter_Data_out <= Cyclic_Program_Counter_Data_in after
100 ps;Cyclic_Target_Register_Address_out <= Cyclic_Target_Register_Address_in
after 100 ps;

58

Cyclic_Destination_Register_Address_out<=Cyclic_Destination_Register_Addr
ess_in after 100 ps;
Load_Data_out <= Load_Data_in after 100 ps;
Execution_Result_out <= Execution_Result_in after 100 ps;
Cyclic_Operation_Code <= Operation_Code_in after 100 ps;
end if;end process;end TIKUWA;

4.1.8 第 2 パイプラインレジスタの記述
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity PR2 isPort ( Target_Register_Address_in : in std_logic_vector(4 downto 0);
Destination_Register_Address_in : in std_logic_vector(4 downto 0);
Program_Counter_Data_in : in std_logic_vector(31 downto 0);
Source_Register_Data_in : in std_logic_vector(31 downto 0);
Target_Register_Data_in : in std_logic_vector(31 downto 0);
Shamt_in : in std_logic_vector(4 downto 0);
Jump_Address_in : in std_logic_vector(25 downto 0);
Sign_Extended_Data_in : in std_logic_vector(31 downto 0);
Operation_Code_in : in std_logic_vector(5 downto 0);
ALU_Function_Code_in : in std_logic_vector(5 downto 0);
Cyclic_Target_Register_Address_out : out std_logic_vector(4 downto 0);
Cyclic_Destination_Register_Address_out : out std_logic_vector(4 downto 0);
Program_Couter_Data_out : out std_logic_vector(31 downto 0);
Source_Register_Data_out : out std_logic_vector(31 downto 0);
Target_Register_Data_out : out std_logic_vector(31 downto 0);
Shamt_out : out std_logic_vector(4 downto 0);
Jump_Address_out : out std_logic_vector(25 downto 0);
Sign_Extended_Data_out : out std_logic_vector(31 downto 0);
Operation_Code_out : out std_logic_vector(5 downto 0);59

ALU_Function_Code_out : out std_logic_vector(5 downto 0);
Clock : in std_logic);end PR2;
architecture TIKUWA of PR2 is
begin
process(Clock)begin
if (Clock'event and Clock='1') thenCyclic_Target_Register_Address_out <= Target_Register_Address_in after 100
ps;
Cyclic_Destination_Register_Address_out<= Destination_Register_Address_in
after 100 ps;
Program_Couter_Data_out <= Program_Counter_Data_in after 100 ps;
Source_Register_Data_out <= Source_Register_Data_in after 100 ps;
Target_Register_Data_out <= Target_Register_Data_in after 100 ps;
Shamt_out <= Shamt_in after 100 ps;
Jump_Address_out <= Jump_Address_in after 100 ps;
Sign_Extended_Data_out <= Sign_Extended_Data_in after 100 ps;
Operation_Code_out <= Operation_Code_in after 100 ps;
ALU_Function_Code_out <= ALU_Function_Code_in after 100 ps;
end if;end process;end TIKUWA;

4.1.9 第 3 パイプラインレジスタの記述
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity PR3 isPort ( Cyclic_Target_Register_Address_in : in std_logic_vector(4 downto 0);
Cyclic_Destination_Register_Address_in : in std_logic_vector(4 downto
0);Address_in : in std_logic_vector(31 downto 0);60

AllZero_in : in std_logic;
Execution_Result_in : in std_logic_vector(31 downto 0);
Target_Register_Data_in : in std_logic_vector(31 downto 0);
ALU_Function_Code_in : in std_logic_vector(5 downto 0);
Operation_Code_in : in std_logic_vector(5 downto 0);
Cyclic_Target_Register_Address_out : out std_logic_vector(4 downto 0);
Cyclic_Destination_Register_Address_out : out std_logic_vector(4downto 0);
Address_out : out std_logic_vector(31 downto 0);
AllZero_out : out std_logic;
Execution_Result_out : out std_logic_vector(31 downto 0);
Target_Register_Data_out : out std_logic_vector(31 downto 0);
ALU_Function_Code_out : out std_logic_vector(5 downto 0);
Operation_Code_out : out std_logic_vector(5 downto 0);
Link_Register_Data_in : in std_logic_vector(31 downto 0);
Link_Register_Data_out : out std_logic_vector(31 downto 0);
Clock : in std_logic);end PR3;
architecture TIKUWA of PR3 is
begin
process(Clock)begin
if (Clock'event and Clock= '1') thenCyclic_Target_Register_Address_out <= Cyclic_Target_Register_Address_in
after 100 ps;
Cyclic_Destination_Register_Address_out<=
Cyclic_Destination_Register_Address_in after 100 ps;
Address_out <= Address_in after 100 ps;
AllZero_out <= AllZero_in after 100 ps;
Execution_Result_out <= Execution_Result_in after 100 ps;
Target_Register_Data_out <= Target_Register_Data_in after 100 ps;
ALU_Function_Code_out <= ALU_Function_Code_in after 100 ps;
Operation_Code_out <= Operation_Code_in after 100 ps;
Link_Register_Data_out <= Link_Register_Data_in after 100 ps;
end if;end process;61

end TIKUWA;

4.1.10 命令メモリの記述
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity IM isPort ( Instruction_Address : in std_logic_vector(31 downto 0);
Instruction_Code : out std_logic_vector(31 downto 0));end IM;architecture TIKUWA of IM is
type Instruction_Memory is array (0 to 63) of std_logic_vector (31 downto 0);
signal ROM : Instruction_Memory :=("00000000000000000000000000000000","00000000000000000000000000000000",↓（省略）↓"00000000000000000000000000000000","00000000000000000000000000000000");
begin
process (Instruction_Address)
begin
Instruction_Code <= ROM(conv_integer("0" & Instruction_Address(7 downto
2)));
end process;end TIKUWA;

4.1.11 データパス記述
library IEEE;
use IEEE.std_logic_1164.all;use IEEE.std_logic_arith.all;62

use IEEE.std_logic_unsigned.all;entity CPU isport (
Reset : in std_logic; Clock : in std_logic;
Result_Exe :out std_logic_vector(31 downto 0);
Result_Mem : out std_logic_vector(31 downto 0);
PC_PC : out std_logic_vector(31 downto 0);SRD : out std_logic_vector(31downto 0);
TRD : out std_logic_vector(31 downto 0);SED : out std_logic_vector(31downto 0));end CPU;architecture RTL of CPU is
component ALU
Port ( Source_Register_Data : in std_logic_vector(31 downto 0);
Target_Register_Data : in std_logic_vector(31 downto 0);
Sign_Extended_Data : in std_logic_vector(31 downto 0);
Operation_Code : in std_logic_vector(5 downto 0);
ALU_Function_Code : in std_logic_vector(5 downto 0);Shamt : in
std_logic_vector(4 downto 0);
AllZero : out std_logic;Execution_Result : out std_logic_vector(31 downto 0));end component ;component ALU2Port ( Program_Counter : in std_logic_vector(31 downto 0);
Sign_Extended_Data : in std_logic_vector(31 downto 0);
Address_Input : in std_logic_vector(25 downto 0);
Source_Register_Data : in std_logic_vector(31 downto 0);
Operation_Code : in std_logic_vector(5 downto 0);
ALU_Function_Code : in std_logic_vector(5 downto 0);
PC_Output : out std_logic_vector(31 downto 0);
Link_Register_Data : out std_logic_vector(31 downto 0));end component ;component IM
Port ( Instruction_Address : in std_logic_vector(31 downto 0);
Instruction_Code : out std_logic_vector(31 downto 0));63

end component ;component PC
Port ( Program_Counter_Input : in std_logic_vector(31 downto 0);
Operation_Code : in std_logic_vector(5 downto 0);
ALU_Function_Code : in std_logic_vector(5 downto 0);AllZero : in std_logic;
Program_Counter_Output : out std_logic_vector(31 downto 0);
Clock : in std_logic;Reset : in std_logic);end component ;component PR0
Port ( Program_Counter_Data_in : in std_logic_vector(31 downto 0);
Instruction_Code_in : in std_logic_vector(31 downto 0);
Cyclic_Program_Counter_Data_in : in std_logic_vector(31 downto 0);
Cyclic_Target_Register_Address_in : in std_logic_vector(4 downto 0);
Cyclic_Destination_Register_Address_in : in std_logic_vector(4 downto 0);
Load_Data_in : in std_logic_vector(31 downto 0);
Execution_Result_in : in std_logic_vector(31 downto 0);
Operation_Code_in : in std_logic_vector(5 downto 0);
Program_Counter_Data_out : out std_logic_vector(31 downto 0);
Sourcd_Register_Address_out : out std_logic_vector(4 downto 0);
Target_Register_Address_out : out std_logic_vector(4 downto 0);
Destination_Register_Address_out : out std_logic_vector(4 downto 0);
Immediate_out : out std_logic_vector(15 downto 0);
Jump_Address_out : out std_logic_vector(25 downto 0);
Operation_Code_out : out std_logic_vector(5 downto 0);
ALU_Function_Code : out std_logic_vector(5 downto 0);
Shamt_out : out std_logic_vector(4 downto 0);
Cyclic_Program_Counter_Data_out : out std_logic_vector(31 downto 0);
Cyclic_Target_Register_Address_out : out std_logic_vector(4 downto 0);
Cyclic_Destination_Register_Address_out : out std_logic_vector(4 downto 0);
Load_Data_out : out std_logic_vector(31 downto 0);
Execution_Result_out : out std_logic_vector(31 downto 0);
Cyclic_Operation_Code : out std_logic_vector(5 downto 0);
Clock : in std_logic );end component ;64

component PR2
Port ( Target_Register_Address_in : in std_logic_vector(4 downto 0);
Destination_Register_Address_in : in std_logic_vector(4 downto 0);
Program_Counter_Data_in : in std_logic_vector(31 downto 0);
Source_Register_Data_in : in std_logic_vector(31 downto 0);
Target_Register_Data_in : in std_logic_vector(31 downto 0);
Shamt_in : in std_logic_vector(4 downto 0);
Jump_Address_in : in std_logic_vector(25 downto 0);
Sign_Extended_Data_in : in std_logic_vector(31 downto 0);
Operation_Code_in : in std_logic_vector(5 downto 0);
ALU_Function_Code_in : in std_logic_vector(5 downto 0);
Cyclic_Target_Register_Address_out : out std_logic_vector(4 downto 0);
Cyclic_Destination_Register_Address_out : out std_logic_vector(4 downto 0);
Program_Couter_Data_out : out std_logic_vector(31 downto 0);
Source_Register_Data_out : out std_logic_vector(31 downto 0);
Target_Register_Data_out : out std_logic_vector(31 downto 0);
Shamt_out : out std_logic_vector(4 downto 0);
Jump_Address_out : out std_logic_vector(25 downto 0);
Sign_Extended_Data_out : out std_logic_vector(31 downto 0);
Operation_Code_out : out std_logic_vector(5 downto 0);
ALU_Function_Code_out : out std_logic_vector(5 downto 0);
Clock : in std_logic);end component ;component PR3
Port ( Cyclic_Target_Register_Address_in : in std_logic_vector(4 downto 0);
Cyclic_Destination_Register_Address_in : in std_logic_vector(4 downto 0);
Address_in : in std_logic_vector(31 downto 0);
AllZero_in : in std_logic;
Execution_Result_in : in std_logic_vector(31 downto 0);
Target_Register_Data_in : in std_logic_vector(31 downto 0);
ALU_Function_Code_in : in std_logic_vector(5 downto 0);
Operation_Code_in : in std_logic_vector(5 downto 0);
Cyclic_Target_Register_Address_out : out std_logic_vector(4 downto 0);
Cyclic_Destination_Register_Address_out : out std_logic_vector(4 downto 0);65Address_out : out std_logic_vector(31 downto 0);
AllZero_out : out std_logic;
Execution_Result_out : out std_logic_vector(31 downto 0);
Target_Register_Data_out : out std_logic_vector(31 downto 0);
ALU_Function_Code_out : out std_logic_vector(5 downto 0);
Operation_Code_out : out std_logic_vector(5 downto 0);
Link_Register_Data_in : in std_logic_vector(31 downto 0);
Link_Register_Data_out : out std_logic_vector(31 downto 0);
Clock : in std_logic);end component ;component cpu_register
Port ( Source_Register_Address : in std_logic_vector(4 downto 0);
Target_Register_Address : in std_logic_vector(4 downto 0);
Destination_Register_Address : in std_logic_vector(4 downto 0);
Cyclic_Target_Register_Address : in std_logic_vector(4 downto 0);
Program_Counter : in std_logic_vector(31 downto 0);
Load_Data : in std_logic_vector(31 downto 0);
Execution_Result : in std_logic_vector(31 downto 0);
Operation_Code : in std_logic_vector(5 downto 0);
Source_Register_Data : out std_logic_vector(31 downto 0);
Target_Register_Data : out std_logic_vector(31 downto 0);
Clock : in std_logic);end component ;component Sign_Extend_Unit
Port ( Immediate : in std_logic_vector(15 downto 0);
Operation_Code : in std_logic_vector(5 downto 0);
Sign_Extended_Data : out std_logic_vector(31 downto 0));end component ;component DataMemory;
Port ( Target_Register_Data : in std_logic_vector(31 downto 0);
Execution_Result : in std_logic_vector(31 downto 0);
Operation_Code : in std_logic_vector(5 downto 0);
Load_Data : out std_logic_vector(31 downto 0));66

end component ;signal fetch : std_logic_vector(255 downto 0);
signal decode : std_logic_vector(360 downto 0);
signal execution : std_logic_vector(277 downto 0);
signal memory : std_logic_vector(277 downto 0);
signal write : std_logic_vector(255 downto 0);
begin
U_ALU : ALU port map( Source_Register_Data => execution(73 downto 42),
Target_Register_Data => execution(105 downto 74),
Sign_Extended_Data => execution(168 downto 137),
Operation_Code => execution(174 downto 169),
ALU_Function_Code => execution(180 downto 175),
Shamt => execution(110 downto 106),
AllZero => execution(213),
Execution_Result => execution(245 downto 214));
U_ALU2 : ALU2 port map( Program_Counter => execution(41 downto 10),
Sign_Extended_Data => execution(168 downto 137),
Address_Input => execution(136 downto 111),
Source_Register_Data => execution(73 downto 42),
Operation_Code => execution(174 downto 169),
ALU_Function_Code => execution(180 downto 175),
PC_Output => execution(212 downto 181),
Link_Register_Data => execution(277 downto 246));
U_IM : IM port map( Instruction_Address => fetch(31 downto 0),
Instruction_Code => fetch(63 downto 32));
U_PC : PC port map( Program_Counter_Input => memory(41 downto 10),
Operation_Code => memory(118 downto 113),
ALU_Function_Code => memory(112 downto 107),
AllZero => memory(42),Program_Counter_Output => fetch(31 downto 0),
Clock => Clock,Reset => Reset);67

U_PR0 : PR0 port map( Program_Counter_Data_in => fetch(31 downto 0),
Instruction_Code_in => fetch(63 downto 32),
Cyclic_Program_Counter_Data_in => memory(182 downto 151),
Cyclic_Target_Register_Address_in => memory(4 downto 0),
Cyclic_Destination_Register_Address_in => memory(9 downto 5),
Load_Data_in => memory(150 downto 119),
Execution_Result_in => memory(74 downto 43),
Operation_Code_in => memory(118 downto 113),
Program_Counter_Data_out => decode(31 downto 0),
Sourcd_Register_Address_out => decode(36 downto 32),
Target_Register_Address_out => decode(41 downto 37),
Destination_Register_Address_out => decode(46 downto 42),
Immediate_out => decode(62 downto 47),
Jump_Address_out => decode(88 downto 63),
Operation_Code_out => decode(94 downto 89),
ALU_Function_Code => decode(100 downto 95),
Shamt_out => decode(105 downto 101),
Cyclic_Program_Counter_Data_out => decode(137 downto 106),
Cyclic_Target_Register_Address_out => decode(142 downto 138),
Cyclic_Destination_Register_Address_out => decode(147 downto 143),
Load_Data_out => decode(179 downto 148),
Execution_Result_out => decode(211 downto 180),
Cyclic_Operation_Code => decode(217 downto 212),
Clock => Clock);
U_PR2 : PR2 port map( target_Register_Address_in => decode(41 downto 37),
Destination_Register_Address_in => decode(46 downto 42),
Program_Counter_Data_in => decode(31 downto 0),
Source_Register_Data_in => decode(249 downto 218),
Target_Register_Data_in => decode(281 downto 250),
Shamt_in => decode(105 downto 101),
Jump_Address_in => decode(88 downto 63),
Sign_Extended_Data_in => decode(313 downto 282),
Operation_Code_in => decode(94 downto 89),
ALU_Function_Code_in => decode(100 downto 95),

68

Cyclic_Target_Register_Address_out => execution(4 downto 0),
Cyclic_Destination_Register_Address_out => execution(9 downto 5),
Program_Couter_Data_out => execution(41 downto 10),Source_Register_Data_out => execution(73 downto 42),
Target_Register_Data_out => execution(105 downto 74),
Shamt_out => execution(110 downto 106),
Jump_Address_out => execution(136 downto 111),
Sign_Extended_Data_out => execution(168 downto 137),
Operation_Code_out => execution(174 downto 169),
ALU_Function_Code_out => execution(180 downto 175),
Clock => Clock);
U_PR3 : PR3 port map( Cyclic_Target_Register_Address_in => execution(4 downto 0),
Cyclic_Destination_Register_Address_in => execution(9 downto 5),
Address_in => execution(212 downto 181),
AllZero_in => execution(213),
Execution_Result_in => execution(245 downto 214),
Target_Register_Data_in => execution(105 downto 74),
ALU_Function_Code_in => execution(180 downto 175),
Operation_Code_in => execution(174 downto 169),
Cyclic_Target_Register_Address_out => memory(4 downto 0),
Cyclic_Destination_Register_Address_out => memory(9 downto 5),
Address_out => memory(41 downto 10),AllZero_out => memory(42),
Execution_Result_out => memory(74 downto 43),
Target_Register_Data_out => memory(106 downto 75),
ALU_Function_Code_out => memory(112 downto 107),
Operation_Code_out => memory(118 downto 113),
Link_Register_Data_in => execution(277 downto 246),
Link_Register_Data_out => memory(182 downto 151),
Clock => Clock);
U_cpu_re : cpu_register port map( Source_Register_Address => decode(36 downto 32),
Target_Register_Address => decode(41 downto 37),
Destination_Register_Address => decode(147 downto 143),
Cyclic_Target_Register_Address => decode(142 downto 138),69

Program_Counter => decode(137 downto 106),
Load_Data => decode(179 downto 148),
Execution_Result => decode(211 downto 180),
Operation_Code => decode(217 downto 212),
Source_Register_Data => decode(249 downto 218),
Target_Register_Data => decode(281 downto 250),
Clock => Clock);
U_Sign_Extend_Unit : Sign_Extend_Unit port map( Immediate => decode(62 downto 47),
Operation_Code => decode(94 downto 89),
Sign_Extended_Data => decode(313 downto 282));
U_DataMemory : DataMemory port map( Target_Register_Data => memory(106 downto 75),
Execution_Result => memory(74 downto 43),
Operation_Code => memory(118 downto 113),
Load_Data => memory(150 downto 119));
process (Clock)begin
SRD <= execution(73 downto 42);
TRD <= execution(105 downto 74);
SED <= decode(313 downto 282);
PC_PC <= fetch(31 downto 0);
Result_Exe <= execution(245 downto 214);
Result_Mem <= decode(211 downto 180);
end process;end RTL;

4.2 シミュレーションおよびその考察
4.1 節での記述シミュレーションを行った。シミュレーションは Instruction
Memory にアセンブラのプログラムを記述し、結果を出力し、その出力結果を
Data Memory に格納してシミュレータのデータと照合するものとした。シミュレーションに用いたプログラムおよびその出力は次の通りである。各機能ブロック記述の段階で各々シミュレーションを行ったが、データパス記述において各パイプ
ラインレジスタでのデータがクロックと同時に通り抜けてしまうエラーが発生した。

70

各パイプラインレジスタの記述に伝搬遅延を設定することによって対処し、その結果、第３章で述べた設計条件をすべて満たしていることと、各ブロック毎で正常に動作していることを確認した。

4.2.1

オーバーフロー動作確認用アセンブラ
命令コード

アセンブラコード"00000000000000000000000000000000",--NOP"00100000000000010000000000000001",--ADDI GPR0,GPR1,HEX[0001]"00111100000000101000000000000000",--LUI GPR0,GPR2,HEX[8000]"00100000000000111111111111111111",--ADDI GPR0,GPR3,HEX[FFFF]"00000000000000000000000000000000",--NOP"00000000000000000000000000000000",--NOP"00000000000000000000000000000000",--NOP"00000000010000110100000000100000",--ADD GPR2,GPR3,GPR8"00000000010000110100100000100001",--ADDU GPR2,GPR3,GPR9"00000000010000010101000000100010",--SUB GPR2,GPR1,GPR10"00000000010000010101100000100011",--SUBU GPR2,GPR1,GPR11"10101100000000010000000000000100",--SW GPR1,1"10101100000000100000000000001000",--SW GPR2,2"10101100000000110000000000001100",--SW GPR3,3"10101100000010000000000000010000",--SW GPR8,4"10101100000010010000000000010100",--SW GPR9,5"10101100000010100000000000011000",--SW
GPR10,6"10101100000010110000000000011100",--SW GPR11,7
このプログラムは加算命令と減算命令を行い、オーバーフローが正常に検出されることを確認するためのものである。DataMemory１にはオペラン
ド１を、２にはオペランド２を、３にはオペランド３が入る。４、５にはオペランド２＋オペランド３の結果を、６、７にはオペランド２―オペラ
ンド１の結果が入る。なお５，７は符号無視の命令である。期待すべき結
果と演算結果は以下の通りである。
期待すべき結果
ADD 命令,ADDU 命令

71

111111111111111111111111111111112+ 100000000000000000000000000000002
1 011111111111111111111111111111112 Over Flow
SUB 命令,SUBU 命令
100000000000000000000000000000002- 000000000000000000000000000000012
1 011111111111111111111111111111112 Over Flow
このプログラムの出力結果は以下のとおりである。

図 4.2

オーバーフロー検証プログラム結果

図 4.3

命令処理波形

このプログラムによってオーバーフローが正常に検出され出力が０になっていることが確認できた。また、符号無視型の演算ではオーバーフローが無視されて結果がそのまま出力され、正常に動作していることが確認でき

72

た。

4.2.2 ロード命令ストア命令動作確認用アセンブラ

このプログラムは、まず ADDI 命令でデーターを一度レジスタに格納し、それを SW 命令でメモリに出力し、再び出力したデータを別のレジスタに格納することで LW 命令、SW 命令の動作確認を行うものである。

"00000000000000000000000000000000",--NOP"00100000000000010000000000000001",--ADDI GPR0,GPR1,1"00100000000000100000000000000100",--ADDI GPR0,GPR2,100"00000000000000000000000000000000",--NOP"00000000000000000000000000000000",--NOP"00000000000000000000000000000000",--NOP"10101100000000010000000000000100",--SW GPR1,1"00000000000000000000000000000000",--NOP"00000000000000000000000000000000",--NOP"00000000000000000000000000000000",--NOP"00000000000000000000000000000000",--NOP"00000000000000000000000000000000",--NOP"10001100000000110000000000000100",--Lw
GPR3,1

出力結果

図 4.4

データメモリの状態

73

図 4.5レジスタの状態

図 4.6

命令処理波形以上の図 4.5、図 4.6 よりレジスタ番号１に入力データ１が入力され、それがデータメモリ１番地に正常に格納され、レジスタ番号３が１になっていることから、LW 命令、SW 命令が正常に動作していることを確認した。

4.2.3 論理演算命令テスト用アセンブラ

命令コード

アセンブラコード"00000000000000000000000000000000",--NOP
74

"00100100000000011010101010101010",--ADDIU GPR0,GPR1,HEX[AAAA]"00111100000000101010101010101010",--LUI GPR0,GPR2,HEX[AAAA]"00100000000000110101010101010101",--ADDI GPR0,GPR3,HEX[5555]"00100000000001001111111111111111",--ADDI GPR0,GPR4,HEX[FFFF]"00000000000000000000000000000000",--NOP"00000000000000000000000000000000",--NOP"00000000001000100100000000100100",--AND GPR1,GPR2,GPR8"00110000001010011010101010101010",--ANDI GPR1,GPR9,HEX[AAAA]"00000000001000110101000000100101",--OR GPR1,GPR3,GPR10"00110100001010110101010101010101",--ORI GPR1,GPR11,HEX[5555]"00000000001000000110000100000000",--SLL GPR1,GPR12,HEX[4]"00000000001000000110100100000010",--SRL GPR1,GPR13,HEX[4]"00000000001000110111000000100111",--NOR GPR1,GPR3,GPR14"00000000001001000111100000100110",--XOR GPR1,GPR4,GPR15"00111000001100000000000011111111",--XORI GPR1,GPR16,HEX[00FF]"00000000001000101000100000101010",--SLT GPR1,GPR2,GPR17"00000000001000101001000000101011",--SLTU GPR1,GPR2,GPR18"00101000010100110101010101010110",--SLTI GPR2,GPR19,HEX[5556]"00101100010101000101010101010110",--SLTIU GPR2,GPR20,HEX[5556]"00001100000000000000000000011010",--JAL PC[26]"00000000000000000000000000000000",--NOP"00000000000000000000000000000000",--NOP"00000000000000000000000000000000",--NOP"00000000000000000000000000000000",--NOP"00001000000000000000000000000000",--J PC[0]"10101100000000010000000000000100",--SW GPR1,1"10101100000000100000000000001000",--SW
GPR2,2"10101100000000110000000000001100",--SW GPR3,3"10101100000001000000000000010000",--SW GPR4,4"10101100000010000000000000010100",--SW GPR8,5"10101100000010010000000000011000",--SW GPR9,6"10101100000010100000000000011100",--SW GPR10,7"10101100000010110000000000100000",--SW
GPR11,8"10101100000011000000000000100100",--SW
GPR12,9"10101100000011010000000000101000",--SW
GPR13,10"10101100000011100000000000101100",--SW
GPR14,1175

"10101100000011110000000000110000",--SW"10101100000100000000000000110100",--SW"10101100000100010000000000111000",--SW"10101100000100100000000000111100",--SW"10101100000100110000000001000000",--SW"10101100000101000000000001000100",--SW"10101100000111110000000001001000",--SW

GPR15,12
GPR16,13
GPR17,14
GPR18,15
GPR19,16
GPR20,17
GPR31,18

期待すべき結果
AND 命令0000AAAAh AND

AAAA0000h=

00000000h

ANDI 命令
0000AAAAh

AND

0000AAAAh=

0000AAAAh

OR 命令
0000AAAAh

OR

00005555h=

0000FFFFh

ORI 命令0000AAAAh

OR

00005555h=

0000FFFFh

SLL 命令0000AAAAh 4 ビット左シフト = 000AAAA0h
SRL 命令0000AAAAh 4 ビット右シフト = 00000AAAh
NOR 命令0000AAAAh NOR 00005555h = FFFF0000h
XOR 命令0000AAAAhXOR

FFFFFFFFh=

FFFF5555h

XORI 命令
0000AAAAh

XOR

000000FFh=

0000AA55h

SLT 命令,SLTU 命令
0000AAAAh < AAAA0000h= 00000001h

SLTI 命令,SLTIU 命令
0000AAAAh < 00005556h= 00000000h

シミュレーション結果は図 4.7、図 4.8 のとおりである。

76

図 4.7

論理演算シミュレーション結果

図 4.8

命令処理波形

図 4.7 はデータメモリの状態を表したものであり、プログラムの SW 命
令により各々の演算結果がデータメモリ出力されたものである。この結果
からこのプログラムにおいてすべての命令は正常に動作していることが確認された。
また、図 4.8 の命令処理波形の Program Counter の値 92 で、次の値が104 となっていることから Jump 命令も正常に動作していることが確認さ
れた。

77

第５章

まとめ

本研究での RISC プロセッサの設計では、今までの講義で得られた知識では不十分であったため、文献やゼミを通して必要な知識を取得するのに大変時間がかかってしまった。今回の設計は、今までの実験で経験したものよりはるかに回路や配線が複雑だったため、各ブロック間での動作確認を行っていても、全体として動作させるとさまざまなところにエラーが生じてしまった。VHDL 記述だけではなく、設計段階でミスがあると規模が大きいほど気付きにくい。かつそれが致命傷になりかねない。基礎段階での十分な設計とテストが必要であることを今回の研究を通して学んだ。また、
VHDL による回路設計を習得できたことも大きな成果だと思う。レジスタ等のメモリアレイが大規模になってしまい、FPGA への実装は出来なかった。
この点をふまえ、今後の課題は、回路設計においてその規模を十分に意識しながら設計を進めていくことである。

78

謝辞
全過程を通じてご指導に当たってくださった矢野政顕教授、適宜ご指導いた
だいた原央教授、橘昌良助教授に厚くお礼申し上げます。また、様々な点で協力してくださった矢野研究室、原研究室、橘研究室の諸氏に感謝します。

79

参考文献
[1],Gerry Kane、前川 守:”mips RISC アーキテクチャ”,共立出版株式会社[2],John L. Hennessy ，David A. Patterson ：“コンピュータの構成と設計 第 2版”,日経 BP 社
[3], K.C.Chang :”Digital Systems Design with CHDL and Synthesis An Integrated
Approach”, IEEE Computer Society
芝山 潔：“コンピュータアーキテクチャの基礎”,近代科学社[4],長谷川 裕恭:”VHDL によるハードウェア設計入門”, CQ 出版社[5],深山 正幸、北川 章夫、秋田 純一、鈴木 正國:”HDL による VLSI 設計”,
共立出版株式会社[6],田丸 啓吉、安浦 寛人:”マイクロコンピュータ”,共立出版株式会社[7],MIPS Technologies Inc. : “MIPS32 4K Processor Core Family Software User’s
Manual” http://www.mips.com/[8],MIPS Technologies Inc. : “MIPS32 4K Processor Core Family Integrator’s
Guide”, http://www.mips.com/

80

ADD命令符号あり算術加算命令

RS:オペランド１

例外

RT:オペランド２
RD:オペランド３

オーバーフロー結果

加算命令発行ALL Zero判定
加数、被加数を２の補数とみなして加算。
先頭１ビットを複写することで、加算によって符号が失われてしまうことを防ぐ。

RSの先頭１ビットを１ビット拡張
RDの先頭１ビットを１ビット拡張

加算
結果＝Temp
桁上げなどによって、符号が失われてしまった場合にはそれをオーバーフローとして出力
Yes

Temp32≠Temp31

Overflowを発行

例外発行

No

RS←Temp

演算終了

ADDU命令符号なし算術加算命令

RS:オペランド１

例外

RT:オペランド２
RD:オペランド３

なし
結果

ALL Zero判定
加算命令発行

この操作はADD命令と互換性を持たせるために残しているもので、無くても支障は無い。

RSの先頭１ビットを１ビット拡張
RDの先頭１ビットを１ビット拡張

加算
結果＝Temp

RS←Temp

演算終了

ⅠADDI命令

Immediate型符号あり算術加算命令

GPR[rs]: 加算される数

例外

Immediate: 加算する数

オーバーフローGPR[rt]: 加算結果

ALL Zero判定

加算命令開始Immediateのデータの先頭1ビットを17ビット分拡張し結合
それにより符号が失われてしまうのを防ぐ
GPR[rs]のデータも同じ理由から符号拡張を行う。

Immediateのデータを33ビットに符号拡張
GPR[rs]の値の先頭1ビットを1ビット拡張

加算
結果＝Temp
桁上げなどによって、符号が失われてしまった場合にはそれをオーバーフローとして出力
Yes

Temp32≠Temp31

Overflowを発行

例外発行

No

GPR[rt]←Temp

演算終了

ADDU命令Immediate型符号なし算術加算命令
例外

GPR[rs]: 加算される数

なし

Immediate: 加算する数

ALL Zero判定

GPR[rt]: 加算結果
加算命令発行

この操作はADDI命令と互換性を持たせるために残しているもので、無くても支障は無い。

Immediateのデータを33ビットに符号拡張
GPR[rs]の値の先頭1ビットを1ビット拡張

加算
結果＝Temp

万が一符号ビットへの桁上げが生じた場合
オーバーフローのトラップを行わないため演算結果が意図したものにならない可能性が有る

GPR[rt]←Temp

演算終了

Ⅱ

SUB命令符号あり算術減算命令

RS:オペランド１

例外

RT:オペランド２
RD:オペランド３

オーバーフロー結果

減算命令発行ALL Zero判定
減数、被減数を２の補数とみなして加算。
先頭１ビットを複写することで、減算によって符号が失われてしまうことを防ぐ。

RSの先頭１ビットを１ビット拡張
RDの先頭１ビットを１ビット拡張

減算
結果＝Temp
桁上げなどによって、符号が失われてしまった場合にはそれをオーバーフローとして出力
Yes

Temp32≠Temp31

Overflowを発行

例外発行

No

RS←Temp

演算終了

SUBU命令符号なし算術減算命令

RS:オペランド１

例外

RT:オペランド２
RD:オペランド３

なし
結果

ALL Zero判定
減算命令発行

この操作はSUB命令と互換性を持たせるために残しているもので、無くても支障は無い。

RSの先頭１ビットを１ビット拡張
RDの先頭１ビットを１ビット拡張

減算
結果＝Temp

RS←Temp

演算終了

ⅢAND命令論理積命令

RS:オペランド１

フラグレジスタ変化

RT:オペランド２

ALL ZERO

RD:オペランド３

結果

論理積命令発行

AND命令では符号の有る無いにかかわらず
それをひとつの数値とみなして、RS、RT間でANDを行う

RD ← RS and RT

演算終了

OR命令

論理和命令

RS:オペランド１

フラグレジスタ変化

RT:オペランド２
RD:オペランド３

ALL ZERO
結果

論理積命令発行

AND命令と同様にして
RS、RT間でORを行う

RD ← RS or RT

演算終了

Ⅳ

ANDI命令

Immediate論理積命令

GPR[rs]: オペランド１

例外

Immediate:オペランド２
GPR[rt]:

なし

結果

命令開始
16ビットのイミーディエートに上位に０を１６ビット分付け加えてゼロ拡張を行う。

Immediateの値をゼロ拡張

GPR[rt] ← (GPR[rs] AND Immediate)

演算終了

ORI命令

Immediate論理和命令

GPR[rs]: オペランド１

例外

Immediate:オペランド２
GPR[rt]:

なし

結果

命令開始
16ビットのイミーディエートに上位に０を１６ビット分付け加えてゼロ拡張を行う。

Immediateの値をゼロ拡張

GPR[rt] ← (GPR[rs] OR Immediate)

演算終了

Ⅴ

BEQ命令(Branch on Equal)

等号条件分岐GPR[rs]: 比較対象
命令開始

GPR[rt]: 比較対象
Offset: 分岐先

等号が成り立つことを減算を行い０出力の結果で判定する。
この演算は基本のALUで行う
Offsetの下位に2ビット分０を結合
GPR[rs] - GPR[rt]例外
結合後の値を32ビットに符号拡張なし

この演算はALUとは別の計算ユニットを設け、そこで計算を行う。

ALL Zero判定(PC + 4) +拡張後のOffset

YES

０判定出力

PCに値を代入

NO

命令終了

BNE命令(Branch on Not Equal)

不等号条件分岐GPR[rs]: 比較対象
命令開始

GPR[rt]: 比較対象

不等号が成り立つことを減算を行い０出力の結果で判定する。
この演算は基本のALUで行う

Offset: 分岐先
Offsetの下位に2ビット分０を結合
GPR[rs] - GPR[rt]例外
結合後の値を32ビットに符号拡張なし

この演算はALUとは別の計算ユニットを設け、そこで計算を行う。

ALL Zero判定(PC + 4) +拡張後のOffset

NO

０判定出力

PCに値を代入

NO

命令終了

Ⅵ

SLT命令大小比較命令rs:比較される数

例外

rt:比較する数

なし

rd:結果格納SLT命令開始

大小比較演算では両方の値を２の補数とみなして減算
その結果の先頭1ビット（符号ビット）が１ならばSLT条件が成り立つものとし、結果として、rdに１を出力

YES[rs] < [rt]NO[rd] ← 1[rd] ← 0

演算終了

SLTU命令符号なし大小比較命令

rs:比較される数

例外

rt:比較する数

なし

rd:比較演算結果格納
SLTU命令開始
先頭に0を結合したことにより、符号ビットを無効化する。
対象の値が２の補数の負数で合った場合には、数値が異なってしまう。
[rs]の先頭に0を結合し、計33ビットとする[rt]の先頭に0を結合し、計33ビットとする
大小比較演算では両方の値を２の補数とみなして減算
その結果の先頭1ビット（符号ビット）が１ならばSLT条件が成り立つものとし、結果としてrdに１を出力
Yes[rs] < [rt]No[rd] ← 0[rd] ← 1

演算終了

Ⅶ

J命令（Jump）

ジャンプ命令Targert: ジャンプアドレス

例外
なし
命令開始

temp← PC[31..28] ¦¦ target ¦¦ 00

PC[31..28] とTargertと0[2]を結合
下位２ビットに０結合することでアドレス例外発生を防ぐ

PC ← 結果

注意点
この命令の直後にJUMPもしくはBranch命令が有る場合
予期せぬ動作をする恐れがある。この場合、NOP命令にて
パイプラインをストールさせる必要がある。

命令終了

JAL命令（Jump And Link）

アドレス格納ジャンプ命令
例外

Targert: ジャンプアドレス

なし

命令開始

PC[31..28] とTargertと0[2]を結合
PCに4を足した値を代入することによって、JR命令にて戻ってきた場合にもう一度この命令を実行してしまうのを防ぐ。
リンクレジスタには汎用レジスタ３１を使用する

リンクレジスタ←PC+4

注意点
この命令の直後にJUMPもしくはBranch命令が有る場合
予期せぬ動作をする恐れがある。この場合、NOP命令にて
パイプラインをストールさせる必要がある。

PC ← 結果

命令終了

Ⅷ

LW命令

32ビットロード命令

GPR[base]:OffsetBase
Offset:例外

Offset

アドレスエラー
命令開始

GPR[rt]:

ロード結果

Offsetの値を32ビットに符号拡張
下位２ビットが０で無い場合にはアドレス例外が発生するので、
下位2ビット分は０で固定し、アドレス例外が発生しないように設計する。

Address ← Offset + GPR[base]

GPR[rt] ← Addressのメモリ内容

命令終了

SW命令

Immediate論理和命令

GPR[rs]: オペランド１

例外

Immediate:オペランド２

アドレスエラー

命令開始

GPR[rt]:

結果

Offsetの値を32ビットに符号拡張

下位２ビットが０で無い場合にはアドレス例外が発生するので、
下位2ビット分は０で固定し、アドレス例外が発生しないように設計する。

Address ← Offset + GPR[base]

Addressのメモリ ← GPR[rt]

演算終了

Ⅸ

SLL命令論理左シフト命令

GPR[rt]:シフト対象データ
shamt:

例外

シフト量

なし

GPR[rd]: シフト結果

シフト命令開始

GPR[ｒｔ]のデータ読み出し

シフト数分
データをシフト31−（シフト数）から０ビットまでのデータに
シフト数分の０を下位ビットに結合することによって１クロックでシフトを実現。

GPR[rd] ←結果

SRL命令

論理右シフト命令

GPR[rt]:シフト対象データ
shamt:

例外

シフト量

なし

GPR[rd]: シフト結果

シフト命令開始

GPR[ｒｔ]のデータ読み出し

シフト数分
データをシフト31−（シフト数）から０ビットまでのデータに
シフト数分の０を上位ビットに結合することによって１クロックでシフトを実現。

GPR[rd] ←結果

Ⅹ

ⅩⅠ

Instruction
Memory

PC

ADD

6

6

32 32

PR１

32

32

5

5

16

32

32

5

5

RT

RS

6

Function

OP CODE

6

Immediate
ビット拡張ユニット

6

Register

RD

RT

6

6

32

32

32

5

5

32

PR１

32

6

6

32

32

32

32

6

ALU

SUB
ALU

6

6

6

32

32

32
PR１
32

32

6

DataMemory