0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

コンピュータアーキテクチャをやろうぜ

Posted at

はじめに

はじめまして、初めて記事を書かせていただくため情報に至らない点があるかもしれませんが、温かい目でいただけると幸いです。

読んだ本

コロナ社から出ている VerilogHDL で学ぶコンピュータアーキテクチャといった本で今回は学びました。

第 1 章 コンピュータアーキテクチャ

この章では基本的なプログラム内蔵方式コンピュータの構成と動作原理を学んだ。

基本動作として

コンピュータの基本構成は入力装置、出力装置、主記憶装置、中央処理装置(制御装置、演算装置)で構成される。その中の核として、中央処理装置(CPU)がある。CPU とメモリの構成としては、制御装置の中に IR(命令レジスタ)、DEC(デコーダー)、PC(プログラムカウンタ)が入り、演算装置の中に REG(レジスタ)、ALU(算術演算処理装置)が入っている。データバス、アドレスバスによってアドレスとデータが移動し、主記憶装置(MM)に送られる。

汎用コンピュータ動作の流れ

基本的な PC の起動の流れとして、電源ユニットで AC100[V]から DC に変換を行いパソコン内部機器で使用できるようにする。その後マザーボードに電流が送られ、CPU、MM その他の周辺機器などの LSI が装着された状態で起動することにより、CPU が起動してから BIOS が起動するといった手順で PC が起動する。

第 2 章 マイクロプロセッサとメインメモリ

マイクロプロセッサは CPU を集積回路(LSI)で表現した回路である。簡単に言うと大量のトランジスタで構成された回路のことで、最近は集積度も上がり、どんどん性能が向上している。

マイクロプロセッサ

基本的に二つの構成に分けられ、CISC と RISC になる。
簡単な違いとしては CISC は命令長が可変で 1 つの命令で多くの処理を行うことができる反面命令によって必要クロック数が異なるため、構造的に最大クロック数が上げにくい面がある。RISC は命令長が固定となって、1 クロックで 1 命令を実行するため構造的に最大動作周波数を上げやすい反面、複雑な処理を行うにはいくつかの命令を組み合わせて実行する必要があるため、最大周波数を CISC 以上に上げる必要がある。

マイクロプロセッサの基本構成

マイクロプロセッサは基本的に CPU、MM、I/O が組み合わさって、データバスとアドレスバスによってつながっている。
I/O の制御方式としては、直接制御方式と間接制御方式がある。直接制御方式は、メモリマップと I/O マップに分けられて、メモリマップは I/O とメモリを同じ領域ののアドレスで制御する。I/O マップは、MM と I/O の領域を別で扱う。間接制御方式は CPU が IOP(チャネル)を通じて、I/O を制御する。チャネルはセレクタチャネルとマルチプレクサチャネルに分けられる。分け方としては、セレクタチャネル(バーストモード)は 1 台の周辺装置が入出力動作の開始から終了までチャネルを占有する。マルチプレクサチャネル(マルチプレクサモード)複数の周辺機器がチャネルを共有する働きをする。

メモリ

記憶階層の速度として、レジスタが最速で次にキャッシュメモリ、MM、HDD 等の順で速度が遅くなり、容量が大きくなる。メモリにはランダムアクセスとシリアルアクセスがある。ランダムアクセスは RAM と ROM がある。
RAM は要はメモリで、種類としては DRAM と SRAM がある。DRAM は、トランジスタとコンデンサで作る。簡単な構造でできるメモリであるが、センスアンプという増幅が必要なためそれを行う時間分遅くなる。SRAM はフリップフロップで構成されるため、高速に動作できる。
ROM は読み取り専用のメモリで不揮発性である。ROM の種類別の変化表は以下に示す。

ROM 種類 特徴
マスク ROM 工場であらかじめデータが入れられていて自分では入れられない ゲームのファームウェア、家電製品
PROM データを一度しか入れられない マイコン
EPROM データの消去が可能な PROM 組込みシステムのファームウェア格納
EEPROM 電気的にデータを消去する EPROM フラッシュメモリ-> SSD

第 3 章 コンピュータの表現と実装

コンピュータはスイッチング回路で構成される。コンピュータはすべての処理が 2 進符号で表現される。

負数の表現

負数表現としては、符号絶対値表現、1 の補数、2 の補数、バイアス表現がある。符号絶対値表現は、MSB が 1 であれば負の数、0 であれば正数である。1 の補数は、ビット反転した表現である。2 の補数は、1 の補数+1 である。バイアス表現(エクセスコード)はいくつかのバイアスを数に追加した表現のことを言う。バイアスは下から押し上げるような表現である。

ステートマシンの表現

ステートマシンは状態の表現をする図のことで、ぶっちゃけ真理値表の方がいいかもしれないと思った。
ここはしっかり理解できていない範囲なのでまた戻って見直します。
とりあえず、ムーア型とミーリー型があって、ムーア型が出力関数が状態のみで決定し、ミーリー型が出力関数を状態と入力で決定する。

第 4 章 Verilog HDL による回路設計

ここでは、 VerilogHDL の記述方法を学んだ。正直ここで初めて、ハードウェア記述言語という物を知ったが、言語の内容としてはそれほど難しいものではなかった。シミュレーションでしかないため、実際の設計の指標でしかないが、ないよりはわかりやすく設計できると感じた。

モジュール

モジュールの例として 4 ビット全加算器のモジュールを示す。
変数の内容はコメントに書いてある通りで、この記述を設計するファイルの一番上に置く。

full_4bit_adder.v
module full_4bit_adder(
    // A: 4ビットの入力データ1
    input  [3:0] A,
    // B: 4ビットの入力データ2
    input  [3:0] B,
    // Cin: 下位からの桁上がり入力 (Carry-in)
    input        Cin,
    // S: 4ビットの加算結果 (Sum)
    output [3:0] S,
    // Cout: 上位への桁上がり出力 (Carry-out)
    output       Cout
);

回路記述方法

この後に、回路の構成を決める。回路の内容としては、組み合わせ回路と順序回路がある。
組み合わせ回路は、assignを用いて定義を行う。以下に全加算器を作る場合の記述である。

full_4bit_adder.v
    // --- 継続的代入による加算処理 ---
    // {Cout, S} はCout(1bit)とS(4bit)を連結した5bitの信号として扱う
    // A(4bit) + B(4bit) + Cin(1bit) の演算結果は最大5bitになる
    // その結果を {Cout, S} に代入することで、上位1bitがCoutに、下位4bitがSにそれぞれ割り当てられる
    assign {Cout, S} = A + B + Cin;

順序回路は、状態の遷移に特定のトリガを必要とする回路である。トリガとしては、主にクロック信号が用いられる。
以下に順序回路例として非同期式 8 進カウンタ回路を示す。

    // alwaysブロックで、クロックの立ち上がりエッジ(posedge CLK)か
    // リセットの立ち下がりエッジ(negedge RESETN)をトリガとする
    // これにより、リセットが非同期で動作する
    always @(posedge CLK or negedge RESETN) begin
        if (!RESETN) begin
            Q <= 3'd0; // 非同期リセット: RESETNが0なら即座にカウンタを0に
        end else if (EN) begin
            // Qが3ビットなので、7(3'b111)の次は自動的に0(3'b000)にラップアラウンドする
            Q <= Q + 1; // イネーブルが1ならクロックの立ち上がりでカウントアップ
        end
    end

ブロッキング代入、ノンブロッキング代入

上記のプログラムを見てプログラムに精通している人なら「?」と感じる部分があると思う。
代入に比較演算子が使われていたり、イコールが使われていたりと同一化されていないと思われていると思う。
その判別としては、ブロッキング代入とノンブロッキング代入で分けられる。
ブロッキング代入とは、分かりやすいイコールで代入を行っている表現である。この表現は A=B, B=C であれば A=C が成り立つといった簡単な論理が複雑さを抜きただ A=C と表現できるようになる。しかし現実の回路としては入れたものを出す単体の回路でしか表現ができないため詳細に回路を構成できない点がある。
ノンブロッキング代入は、<=を用いて代入を行う。A=B と B=C であることを個別に扱うため、別の回路のとして扱える事によって、より詳細に回路が表現できる。

第 5 章 レジスタ、カウンタ要素

この章では、CPU の命令やデータの一時格納場所として使われるレジスタと、プログラム制御の基準となるカウンタを学んだ。

カウンタ

カウンタの構成としては、基本的に D フリップフロップで構成されるものと、T フリップフロップで構成されるものがある。構成方法が違うだけで作れる物自体にそこまで違うは無いように感じた。
カウンタの HDL の例としては、以下のようになる。以下は 4 ビットカウンタなので、1 ~ 8 まで数えてリセットする又はリセットが入力されたらカウンタの動作をやり直すといった処理を行う。

counter.v
module COUNTER_RTL(
    input RESET, //  リセット入力
    input CLK, // クロック入力
    output reg [3:0] COUNT // カウンタ出力
);

    always @(posedge CLK) begin // ポジティブエッジ動作
        if(RESET == 1'b1 | COUNT == 4'hF) begin
            COUNT <= 4'h0; // リセットまたはカウントが最大値に達した場合、カウントをリセット
        end
        else begin
            COUNT <= COUNT + 4'h1; // カウントをインクリメント
        end
    end
endmodule

レジスタ

レジスタの種類として、汎用レジスタ、命令レジスタ、プログラムレジスタ、フラグレジスタがある。
汎用レジスタは演算結果の一時格納場所として利用される。命令レジスタはメモリから読みだされた命令を格納する。
プログラムレジスタはプログラムを行うアドレスを一時的に格納する。フラグレジスタは、演算結果から次の処理を決めるため選択を一時的に格納をする。
レジスタの種類として、さらにシフトレジスタがある。シフトレジスタは時間的に連続して入力した値を並列に出力するレジスタである。以下にレジスタの基本構造とシフトレジスタの基本構造を示す。

register.v
module REGN(CLK, RESET, D, Q);
    parameter  N = 8; // bit数Nを指定
    input CLK;
    input RESET;
    input [N - 1:0] D;
    output [N - 1: 0] Q;
    reg [N - 1:0] Q; // 出力はQの値をレジスタとして保持

always @(posedge CLK) begin // クロック信号CLKの立ち上がりタイミングで動作
    if(RESET) // RESET = 1の場合
        Q <= 0; // CLKの立ち上がりタイミングで出力Qより0を出力
    else
        Q <= D; // 入力DをCLKの立ち上がりタイミングで取り込みQへ出力
end
endmodule
shift_register.v
module SHIFT_REG(
    input CLK, // クロック入力
    input RESET, // リセット入力
    input D, // データ入力
    output reg [3:0] Q=4'b0000 // 出力レジスタ
);

    always @(posedge CLK) begin
        if(RESET) begin
            Q <= 4'b0000;
        end
        else begin
            Q <= {Q[2:0], D}; // 入力Dが4ビット内を移動し、他を0とする。
        end
    end
endmodule

祭 6 章 演算要素

この章では、CPU 内部の演算装置である ALU の基本的な構造を学んだ。

演算装置

まず、半加算器、全加算器のような加算器から学び、複数ビットでの加算、加減算器、比較器、シフト演算器、乗算器までを学んだ。
半加算器は桁上げが起こらない加算をするだけである。全加算器は桁上げまで表現できる。
複数ビットの表現は全加算器を繋げることによって桁数を引き上げる。比較器では XNOR ゲートを用いての表現や NOR 回路などでより詳細に表現できる。
シフト演算は論述シフトと算術シフトがあり、論述シフトはただビットシフトをするだけであるが、算術シフトは上位シフトの移動幅で乗算を表現し、下位シフトの移動幅で除算を表す。さらに MSB で正の値か負の値を表現する。
乗算は基本的には、加算器と、シフトレジスタでのみで構成できる。やり方によっては全加算器でも表現できる。
まとめて計算できる機能を含んだ装置を ALU と呼ぶ。

第 7 章 制御要素

この章では命令の与える ALU、メモリ、レジスタの制御を行うために使う制御装置について学んだ。
基本的には、エンコーダ、デコーダを用いる。

デコーダ

デコーダの基本的な機能としては、出力のうち 1 つのみが 1 となり、入力の組み合わせによって出力する対象が変わる。デコーダの構成例として、4 ビットの 2 進数から 10 ビットの 2 進数の単体の値(10 進数)に変換する場合を以下に表現する。

decoder.v
module DECODER(
    input [3:0] X,
    output reg [9:0] Y
);

always @(*)
begin
    case(X) // 2進数の値を10ビット中の1ビットに立つようにする。
        4'b0000: Y = 10'b0000000001;
        4'b0001: Y = 10'b0000000010;
        4'b0010: Y = 10'b0000000100;
        4'b0011: Y = 10'b0000001000;
        4'b0100: Y = 10'b0000010000;
        4'b0101: Y = 10'b0000100000;
        4'b0110: Y = 10'b0001000000;
        4'b0111: Y = 10'b0010000000;
        4'b1000: Y = 10'b0100000000;
        4'b1001: Y = 10'b1000000000;
        default: Y = 10'b1111111111; // 値が何も入っていない場合はこれになる
    endcase
end
endmodule

エンコーダ

エンコーダは、デコーダと逆のことを起こすことである。エンコーダは立ってる 1 つのビットを 2 進数、16 進数などに変換する装置である。基本的にはデコーダとセットで使用する。
以下にエンコーダの設計例を示す。
8 ビットの中である値が立った時に 2 進数で表現するといった装置である。

encoder.v
module ENCODER(
    input [7:0] X,
    output reg [2:0] Y
);

always @(*)
begin
    case(X)
        8'b00000001: Y <= 3'b000;
        8'b00000010: Y <= 3'b001;
        8'b00000100: Y <= 3'b010;
        8'b00001000: Y <= 3'b011;
        8'b00010000: Y <= 3'b100;
        8'b00100000: Y <= 3'b101;
        8'b01000000: Y <= 3'b110;
        8'b10000000: Y <= 3'b111;
        default: Y <= 3'b111;
    endcase
end
endmodule

マルチプレクサ

マルチプレクサは複数の入力信号から 1 つを選択し、出力に伝搬させる回路である。
以下に 2 進数 2 ビットで 4 ビット内の 1 ビットが順番に出力される装置である。

MULTIPLEXER.v
module MULTIPLEXER(
    input [3:0] D,
    input [1:0] SELECT,
    output reg F
);

always @(*)
begin
    case(SELECT)
        2'b00: F = D[0];
        2'b01: F = D[1];
        2'b10: F = D[2];
        2'b11: F = D[3];
        default: F = D[0];
    endcase
end
endmodule

デマルチプレクサ

デマルチプレクサは逆に複数の出力信号から、1 つの信号を選択し、入力信号を伝搬させる装置である。
以下にデマルチプレクサの複数出力 F[0]~F[3]のどれかに出力されるように入力される信号に変換する装置である。

DEMULTIPLEXER.v
module DEMULTIPLEXER(
    input D,
    input [1:0] SELECT,
    output reg [3:0] F
);

always @(*)
begin
    case(SELECT)
        2'b00: F = {D, 3'b000};
        2'b01: F = {1'b0, D, 2'b00};
        2'b10: F = {2'b00, D, 1'b0};
        2'b11: F = {3'b000, D};
        default: F = {4'b0000};
    endcase
end
endmodule

第 8 章 コンピュータの命令

この章では、CPU で実際に実行されている命令は命令セットに組み込まれたもので実行されるため、PC で行われる高水準言語を CPU であった処理に変更して行われる。\

代表的な命令

基本的な CPU の命令パターンとしては、LD、ST、ADD、SUB、CP、CPA、SLA、JPL、POP、CALL、NOP などの命令がある。個々の命令の詳細は以下の表に示す。

命令 機能
LD メモリを指定アドレスからレジスタへデータを転送する
ST レジスタのデータをメモリへ書き出す
LAD 実行アドレス値を計算してレジスタに保存する
ADDA、ADDL 符号付き加算、符号なし加算
SUBA、SUBL 符号付き減算、符号なし減算
CPA、CPL 符号付き比較、符号なし比較
SLA、SAR 算術左シフト、算術右シフト
SLL、SRL 論理左シフト、論理右シフト
JPL 正分岐(SF=0 AND ZF=0)
JMI 負分岐(SF=1)
JNZ 非零分岐(ZF=0)
JZE 零分岐(ZF=1)
JOV オーバーフロー分岐(OF=1)
PUSH スタックポインタを 1 減らしたうえで、スタックポインタで示されるアドレスに実効アドレスを書き込む
POP スタックポインタで示されるアドレスに保存した値をレジスタ r に保存した後、スタックポインタを 1 増やす
CALL ➀ スタックポインタをデクリメント ➁ スタックへ現在のプログラムカウンタの値を保存 ➂ プログラムカウンタに実効アドレスを保存
RET ➀ スタックに保存したプログラムカウンタの値をプログラムカウンタへ書き戻す ➁ スタックポインタをインクリメントする
NOP 無操作

第 9 章 コンピュータの高速化技術と信頼性

この章では、現在のコンピュータがどのような技術を用いて、高速化、信頼性を保っているのかを学んだ。

マルチプログラミング

基本的な CPU が処理できるのは 1 つの処理だけであるが、これは処理にアイドルタイムが生じた場合にほかのプログラムに切り替え処理を行い
処理を続けることをマルチプログラミングと言う。マルチプログラミングは単純に実行時間の短縮につながる。

キャッシュメモリ

キャッシュメモリとは、メモリから一時的にデータをコピーして、格納されたデータを CPU と高速にやり取りすることができる装置である。
キャッシュメモリは階層化されている場合がある。キャッシュメモリは、1 次キャッシュ、2 次キャッシュと変化し、1 次キャッシュの方が高速である構造となっている。
キャッシュにはキャッシュミスが発生する。キャッシュミスは CPU がキャッシュメモリ内にデータが存在しな場合、メモリにデータをコピーしに行く必要があるため、この時間が発生することをキャッシュミスと言う。そのキャッシュメモリと MM の同一性をコヒーレンシという。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?