デジタル集積回路の設計課題:順序論理とメモリの実装例

1. 基礎概念問題

1.1 ミーリ状態機械とムーア状態機械の特性と相互関係について説明してください。

ムーア状態機械:出力が現在の状態のみに依存する状態機械。

ミーリ状態機械:出力が現在の状態だけでなく入力にも依存する状態機械。

ミーリ機械とムーア機械は相互に変換可能です。任意のミーリ機械に対して等価なムーア機械が存在し、そのムーア機械の状態数は対応するミーリ機械の状態数と出力数の積を上限とします。

1.2 SRAMの特性と、実際の応用におけるレジスタファイル論理との長所と短所の比較について説明してください。

SRAMの特性:動作速度が高速であり、電源が供給されている限り書き込まれた情報は保持され、リフレッシュ回路が不要です。読み出し時に元の情報が破壊されることがなく、一度書き込むと何度でも読み出せます。しかし、集積度は低く、消費電力は大きいという欠点があります。

レジスタファイル論理:実装がよりシンプルですが、プロセス最適化されたSRAMには性能が及びません。一方、SRAMは性能に優れますが、実装がやや複雑になります。

1.3 ゲーテッドクロックの一般的な回路構造と適用範囲について説明してください。

ゲーテッドクロックの回路構造:

  • 制御信号とクロック信号を直接AND演算する方式(グリッチが発生するため、実際にはほとんど使用されません)
  • ラッチャベースのクロックゲーティング方式(ASIC設計でよく使用)
  • フリップフロップベースのクロックゲーティング方式(FPGA設計でよく使用)

1.4 AHBバスとAPBバスの基本特性と、実際のSoCシステムにおける適用場面について説明してください。

AHB(Advanced High-performance Bus):高速バスで、通常高速周辺機器の接続に使用されます。

APB(Advanced Peripheral Bus):低速バスで、通常低速周辺機器の接続に使用されます。

SoCシステムでは、AHBバスにARMプロセッサ、RAM、DMAコントローラなどのデバイスが接続され、AHB2APBブリッジを介してAPBバスに接続されます。APBバスにはUART、タイマなどの低速デバイスが接続されます。

2. Verilog HDLを用いた論理回路設計

2.1 平方根計算回路

32ビット非負整数の平方根を計算する順序論理回路を設計します。入力xに対して、y = floor(sqrt(x))を計算します。ここでyは、2乗した値がxを超えない最大の非負整数です。

例:

  • 入力x = 256、出力y = 16
  • 入力x = 255、出力y = 15
  • 入力x = 2147483648、出力y = 46340
  • 入力x = 4294967295、出力y = 65535

トップモジュール名はsqrt_calculatorとし、入出力機能は以下のように定義します:

名前方向ビット幅説明
clkI1システムクロック
rst_nI1システム非同期リセット、Low有効
data_validI1入力データ有効指示
input_valI32入力値(被開平数)
result_validO1出力データ有効指示
output_valO16出力結果

設計要件:

  • Verilog実装コードは合成可能であること
  • 複数のデータ入力を処理できること
  • データ入力から結果出力までの遅延サイクル数をできるだけ少なくすること
設計アプローチ:

初期検討したCORDICアルゴリズムやニュートン法では、32ビット入力に対して収束しない問題があったため、逐次近似法を採用しました。これは逆方向のニュートン法と理解できます。

逐次近似アルゴリズムの流れ:まずデータ入力を受け取り、試行値と確定値を設定し、上位ビットから順に各ビットを1に設定します。試行値の2乗を入力データと比較し、試行値の2乗が入力値より大きい場合はそのビットを0に、そうでない場合は1に設定します。これを最下位ビットまで繰り返します。

コード実装:
module sqrt_calculator (
    input clk,
    input rst_n,
    input data_valid,
    input [31:0] input_val,
    output reg result_valid,
    output reg [15:0] output_val
);
    parameter DATA_WIDTH = 32;
    parameter RESULT_WIDTH = 16;

    reg     [DATA_WIDTH-1:0] data_reg     [RESULT_WIDTH:1]; 
    reg     [RESULT_WIDTH-1:0] trial_val   [RESULT_WIDTH:1]; 
    reg     [RESULT_WIDTH-1:0] result_val  [RESULT_WIDTH:1]; 
    reg     valid_flag          [RESULT_WIDTH:1]; 

    always@(posedge clk or negedge  rst_n)
        begin
            if(!rst_n)
                begin
                    data_reg[RESULT_WIDTH] <= 0;
                    trial_val[RESULT_WIDTH] <= 0;
                    result_val[RESULT_WIDTH] <= 0;
                    valid_flag[RESULT_WIDTH] <= 0;
                end
            else if(data_valid)
                begin
                    data_reg[RESULT_WIDTH] <= input_val; 
                    trial_val[RESULT_WIDTH] <= {1'b1,{(RESULT_WIDTH-1){1'b0}}}; 
                    result_val[RESULT_WIDTH] <= 0; 
                    valid_flag[RESULT_WIDTH] <= 1;
                end
            else
                begin
                    data_reg[RESULT_WIDTH] <= 0;
                    trial_val[RESULT_WIDTH] <= 0;
                    result_val[RESULT_WIDTH] <= 0;
                    valid_flag[RESULT_WIDTH] <= 0;
                end
        end

        generate
            genvar i; 
                for(i=RESULT_WIDTH-1;i>=1;i=i-1)
                    begin:SQRT_STAGE
                        always@(posedge clk or negedge  rst_n)
                            begin
                                if(!rst_n)
                                    begin
                                        data_reg[i] <= 0;
                                        trial_val[i] <= 0;
                                        result_val[i] <= 0;
                                        valid_flag[i] <= 0;
                                    end
                                else    if(valid_flag[i+1])
                                    begin
                                        if(trial_val[i+1]*trial_val[i+1] > data_reg[i+1])
                                            begin
                                                trial_val[i] <= {result_val[i+1][RESULT_WIDTH-1:i],1'b1,{{i-1}{1'b0}}};
                                                result_val[i] <= result_val[i+1];
                                            end
                                        else
                                            begin
                                                trial_val[i] <= {trial_val[i+1][RESULT_WIDTH-1:i],1'b1,{{i-1}{1'b0}}};
                                                result_val[i] <= trial_val[i+1];
                                            end
                                        data_reg[i] <= data_reg[i+1];
                                        valid_flag[i] <= 1;
                                    end
                                else
                                    begin
                                        valid_flag[i] <= 0;
                                        data_reg[i] <= 0;
                                        result_val[i] <= 0;
                                        trial_val[i] <= 0;
                                    end
                            end
                    end
        endgenerate

        always@(posedge clk or negedge  rst_n) 
            begin
                if(!rst_n)
                    begin
                        output_val <= 0;
                        result_valid <= 0;
                    end
                else    if(valid_flag[1])
                    begin
                        if(trial_val[1]*trial_val[1] > data_reg[1])
                            begin
                                output_val <= result_val[1];
                                result_valid <= 1;
                            end
                        else
                            begin
                                output_val <= {result_val[1][RESULT_WIDTH-1:1],trial_val[1][0]};
                                result_valid <= 1;
                            end
                    end
                else
                    begin
                        output_val <= 0;
                        result_valid <= 0;
                    end
            end

endmodule
テストベンチ:
module sqrt_testbench ();
    
    reg clk, rst_n, data_valid;
    reg [31:0] input_val;
    wire result_valid;
    wire [15:0] output_val;

    initial begin
        clk <= 1'b0;
        rst_n <= 1'b0;
        data_valid <= 1'b0;
        input_val <= 0;
        #30
        rst_n <= 1'b1;
        data_valid <= 1'b1;
        input_val <= 256;
        #20
        input_val <= 255;
        #20
        input_val <= 2147483648;
        #20 
        input_val <= 4294967295;
    end

    always #10 clk <= ~clk;

    sqrt_calculator u_sqrt(
        .clk(clk),
        .rst_n(rst_n),
        .data_valid(data_valid),
        .input_val(input_val),
        .result_valid(result_valid),
        .output_val(output_val)
    );

endmodule

2.2 データソート回路

入力された32個の8ビット符号なし整数を小さい順にソートする順序論理回路を設計します。同じ値のデータが複数ある場合は、それらの順序は問いません。

例:

  • 入力32個のデータ:31, 29, 27, 25, 23, 21, 19, 17, 15, 13, 11, 9, 7, 5, 3, 1, 2, 2, 4, 4, 4, 4, 8, 16, 8, 16, 32, 32, 0, 10, 20, 30
  • 出力32個のデータ:0, 1, 2, 2, 3, 4, 4, 4, 4, 5, 7, 8, 8, 9, 10, 11, 13, 15, 16, 16, 17, 19, 20, 21, 23, 25, 27, 29, 30, 31, 32, 32

トップモジュール名はdata_sorterとし、入出力機能は以下のように定義します:

名前方向ビット幅説明
clkI1システムクロック
rst_nI1システム非同期リセット、Low有効
input_validI1入力データ有効指示
data_in[0:31]I8入力データ配列
output_validO1出力データ有効指示
data_out[0:31]O8出力データ配列(ソート済み)

設計要件:

  • Verilog実装コードは合成可能であること
  • 論理リソースと遅延のトレードオフを考慮し、データ入力から結果出力までの遅延サイクル数をできるだけ少なくすること
設計アプローチ:

双調ソーティングネットワークを検討しましたが、重複データの扱いに課題がありました。バブルソートはリソース消費は少ないですが、遅延が大きくなるため、状態機械を用いた制御で実装します。

コード実装:
module data_sorter (
    input clk,
    input rst_n,
    input input_valid,
    input [7:0] data_in[0:31],
    output reg output_valid,
    output [7:0] data_out[0:31]
);

    parameter IDLE = 2'b00;
    parameter LOAD = 2'b01;
    parameter SORT = 2'b10;
    parameter DONE = 2'b11;

    reg [4:0] counter, pass_count;
    reg [7:0] sort_buffer[0:31];
    reg [1:0] current_state, next_state;
    reg reset_signal, load_signal, swap_signal;

    integer i;

    always @(posedge clk or negedge rst_n) begin
        if(rst_n == 1'b0) begin
            current_state <= IDLE;
        end
        else begin
            current_state <= next_state;
        end
    end

    always @(posedge clk) begin
        if(reset_signal == 1'b1) begin
            for (i = 0; i < 32; i = i + 1) begin
                sort_buffer[i] <= 0;
            end
            pass_count <= 0;
            counter <= 0;
        end
        else if(load_signal == 1'b1) begin
            for (i = 0; i < 32; i = i + 1) begin
                sort_buffer[i] <= data_in[i];
            end
            pass_count <= 31;
            counter <= 0;
        end
        else if(swap_signal == 1'b1) begin
            if(counter < pass_count) begin
                counter <= counter + 1;
                if(sort_buffer[counter+1] < sort_buffer[counter]) begin
                    sort_buffer[counter+1] <= sort_buffer[counter];
                    sort_buffer[counter] <= sort_buffer[counter+1];
                end
            end
            else begin
                counter <= 1;
                pass_count <= pass_count - 1;
                if(sort_buffer[1] < sort_buffer[0]) begin
                    sort_buffer[1] <= sort_buffer[0];
                    sort_buffer[0] <= sort_buffer[1];
                end
            end
        end
    end

    always @(counter, current_state, pass_count, input_valid) begin
        next_state <= IDLE;
        case (current_state)
            IDLE : begin
                reset_signal <= 1'b1;
                output_valid <= 1'b0;
                next_state <= LOAD;
            end 
            LOAD : begin
                reset_signal <= 1'b0;
                if(input_valid == 1'b1) begin
                    load_signal <= 1'b1;
                    output_valid <= 1'b0;
                    next_state <= SORT;
                end
                else begin
                    next_state <= LOAD;
                end
            end
            SORT : begin
                swap_signal <= 1'b1;
                load_signal <= 1'b0;
                if(pass_count == 1 && counter == 1) begin
                    next_state <= DONE;
                    output_valid <= 1'b1;
                end
                else begin
                    next_state <= SORT;
                end
            end
            DONE : begin
                next_state <= LOAD;
                swap_signal <= 1'b0;
            end
            default : begin
                next_state <= IDLE;
            end
        endcase
    end

    genvar j;
    generate
        for(j = 0; j < 32; j = j + 1) begin:OUTPUT_ASSIGN
            assign data_out[j] = sort_buffer[j];
        end
    endgenerate
    
endmodule
テストベンチ:
module sort_testbench ();
    
    reg clk, rst_n, input_valid;
    reg [7:0] data_in[0:31];
    wire output_valid;
    wire [7:0] data_out[0:31];

    integer k;

    initial begin
        rst_n <= 1'b0;
        clk <= 1'b0;
        input_valid <= 1'b0;
        data_in[0]  <= 31;
        data_in[1]  <= 29;
        data_in[2]  <= 27;
        data_in[3]  <= 25;
        data_in[4]  <= 23;
        data_in[5]  <= 21;
        data_in[6]  <= 19;
        data_in[7]  <= 17;
        data_in[8]  <= 15;
        data_in[9]  <= 13;
        data_in[10] <= 11;
        data_in[11] <= 9;
        data_in[12] <= 7;
        data_in[13] <= 5;
        data_in[14] <= 3;
        data_in[15] <= 1;
        data_in[16] <= 2;
        data_in[17] <= 2;
        data_in[18] <= 4;
        data_in[19] <= 4; 
        data_in[20] <= 4; 
        data_in[21] <= 4; 
        data_in[22] <= 8;
        data_in[23] <= 16;
        data_in[24] <= 8; 
        data_in[25] <= 16;
        data_in[26] <= 32;
        data_in[27] <= 32;
        data_in[28] <= 0; 
        data_in[29] <= 10;
        data_in[30] <= 20;
        data_in[31] <= 30;
        #30
        rst_n <= 1'b1;
        input_valid <= 1'b1;
        #20
        input_valid <= 1'b0;
    end

    always #10 clk <= ~clk;

    data_sorter u_sorter(
        .clk(clk),
        .rst_n(rst_n),
        .input_valid(input_valid),
        .data_in(data_in),
        .output_valid(output_valid),
        .data_out(data_out)
    );

endmodule

2.3 ジグザグスキャン回路

8x8の行列ブロックをジグザグパターンでスキャンし、データを再配置する順序論理回路を設計します。入力は行優先方式の64個のデータで、出力はジグザグスキャン順のデータです。

例:

  • 入力64個のデータ:1, 2, 3, 4, ..., 61, 62, 63, 64
  • 出力64個のデータ:1, 2, 9, 17, 10, 3, ..., 62, 55, 48, 56, 63, 64

トップモジュール名はzigzag_scannerとし、入出力機能は以下のように定義します:

名前方向ビット幅説明
clkI1システムクロック
rst_nI1システム非同期リセット、Low有効
input_validI1入力データ有効指示
data_inI10入力データ
output_validO1出力データ有効指示
data_outO10出力データ

設計要件:

  • Verilog実装コードは合成可能であること
  • SRAMを使用して入力データをキャッシュすること
  • データ入力から結果出力までの遅延サイクル数をできるだけ少なくすること
設計アプローチ:

SRAMに64個のデータを保存し、入力時はアドレスを順次増加させ、読み出し時は状態機械でジグザグスキャンに対応するアドレス変化を実装します。

コード実装:
module zigzag_scanner (
    input clk,
    input rst_n,
    input input_valid,
    input [9:0] data_in,
    output reg output_valid,
    output [9:0] data_out
);

    reg chip_select, write_enable, read_enable;
    reg [5:0] address;

    always @(posedge clk or negedge rst_n) begin
        if (rst_n == 1'b0) begin
            address <= 6'b11_1111;
            chip_select <= 1'b1;
            write_enable <= 1'b0;
            read_enable <= 1'b0;
            output_valid <= 1'b0;
        end
        else if (input_valid) begin
            write_enable <= 1'b1;
            chip_select <= 1'b0;
            address <= address + 1'b1;
        end
        else begin
            output_valid <= 1'b1;
            read_enable <= 1'b1;
            case (address)
                6'b11_1111 : address <= 6'b00_0000;
                6'b00_0000 : address <= 6'b00_0001;
                6'b00_0001 : address <= 6'b00_1000;
                6'b00_1000 : address <= 6'b01_0000;
                6'b01_0000 : address <= 6'b00_1001;
                6'b00_1001 : address <= 6'b00_0010;
                6'b00_0010 : address <= 6'b00_0011;
                6'b00_0011 : address <= 6'b00_1010;
                6'b00_1010 : address <= 6'b01_0001;
                6'b01_0001 : address <= 6'b01_1000;
                6'b01_1000 : address <= 6'b10_0000;
                6'b10_0000 : address <= 6'b01_1001;
                6'b01_1001 : address <= 6'b01_0010;
                6'b01_0010 : address <= 6'b00_1011;
                6'b00_1011 : address <= 6'b00_0100;
                6'b00_0100 : address <= 6'b00_0101;
                6'b00_0101 : address <= 6'b00_1100;
                6'b00_1100 : address <= 6'b01_0011;
                6'b01_0011 : address <= 6'b01_1010;
                6'b01_1010 : address <= 6'b10_0001;
                6'b10_0001 : address <= 6'b10_1000;
                6'b10_1000 : address <= 6'b11_0000;
                6'b11_0000 : address <= 6'b10_1001;
                6'b10_1001 : address <= 6'b10_0010;
                6'b10_0010 : address <= 6'b01_1011;
                6'b01_1011 : address <= 6'b01_0100;
                6'b01_0100 : address <= 6'b00_1101;
                6'b00_1101 : address <= 6'b00_0110;
                6'b00_0110 : address <= 6'b00_0111;
                6'b00_0111 : address <= 6'b00_1110;
                6'b00_1110 : address <= 6'b01_0101;
                6'b01_0101 : address <= 6'b01_1100;
                6'b01_1100 : address <= 6'b10_0011;
                6'b10_0011 : address <= 6'b10_1010;
                6'b10_1010 : address <= 6'b11_0001;
                6'b11_0001 : address <= 6'b11_1000;
                6'b11_1000 : address <= 6'b11_1001;
                6'b11_1001 : address <= 6'b11_0010;
                6'b11_0010 : address <= 6'b10_1011;
                6'b10_1011 : address <= 6'b10_0100;
                6'b10_0100 : address <= 6'b01_1101;
                6'b01_1101 : address <= 6'b01_0110;
                6'b01_0110 : address <= 6'b00_1111;
                6'b00_1111 : address <= 6'b01_0111;
                6'b01_0111 : address <= 6'b01_1110;
                6'b01_1110 : address <= 6'b10_0101;
                6'b10_0101 : address <= 6'b10_1100;
                6'b10_1100 : address <= 6'b11_0011;
                6'b11_0011 : address <= 6'b11_1010;
                6'b11_1010 : address <= 6'b11_1011;
                6'b11_1011 : address <= 6'b11_0100;
                6'b11_0100 : address <= 6'b10_1101;
                6'b10_1101 : address <= 6'b10_0110;
                6'b10_0110 : address <= 6'b01_1111;
                6'b01_1111 : address <= 6'b10_0111;
                6'b10_0111 : address <= 6'b10_1110;
                6'b10_1110 : address <= 6'b11_0101;
                6'b11_0101 : address <= 6'b11_1100;
                6'b11_1100 : address <= 6'b11_1101;
                6'b11_1101 : address <= 6'b11_0110;
                6'b11_0110 : address <= 6'b10_1111;
                6'b10_1111 : address <= 6'b11_0111;
                6'b11_0111 : address <= 6'b11_1110;
                6'b11_1110 : address <= 6'b11_1111;
            endcase
        end
    end

    memory_block #(
        .ADDR_WIDTH(6),
        .DATA_WIDTH(10),
        .MEMORY_SIZE(64)
    ) u_memory (
        .clk(clk),
        .rst_n(rst_n),
        .cs_n(chip_select),
        .we_n(write_enable),
        .re_n(read_enable),
        .addr(address),
        .data_in(data_in),
        .data_out(data_out)
    );

endmodule
メモリブロック:
module memory_block #(
    parameter ADDR_WIDTH = 4,
    parameter DATA_WIDTH = 8,
    parameter MEMORY_SIZE = 16
)(
    input clk,
    input rst_n,
    input cs_n,
    input we_n,
    input re_n,
    input [ADDR_WIDTH-1:0] addr,
    input [DATA_WIDTH-1:0] data_in,
    output reg [DATA_WIDTH-1:0] data_out
);
    
    reg [DATA_WIDTH-1:0] memory [MEMORY_SIZE-1:0];
    integer i;

    always @(posedge clk or negedge rst_n) begin
        if (rst_n == 1'b0) begin
            for (i = 0; i < MEMORY_SIZE; i=i+1) begin
                memory[i] <= 0;
            end
        end
        else if (we_n == 1'b1 && cs_n == 1'b0) begin
            memory[addr] <= data_in;
        end
    end

    always @(posedge clk or negedge rst_n) begin
        if (rst_n == 1'b0) begin
            data_out <= 0;
        end
        else if (re_n == 1'b1 && cs_n == 1'b0) begin
            data_out <= memory[addr];
        end
        else begin
            data_out <= data_out;
        end
    end

endmodule

2.4 AHB-SRAMコントローラ

AHBスレーブインターフェースに基づくシングルポートSRAMコントローラを設計し、SRAMメモリとAHBバス間のデータ交換を実現します。AHBバス上の読み書き操作を標準SRAM読み書き操作に変換します。

SRAMサイズは4096x32ビット、AHBインターフェースデータサイズは固定32ビット、AHBインターフェースアドレス範囲は0x00000000~0x00003FFCです。シングルまたはバーストモードのデータ読み書き操作を実現します。

トップモジュール名はahb_sram_controllerとし、入出力機能は以下のように定義します:

名前方向ビット幅説明
hclkI1システムクロック
hresetnI1システム非同期リセット、Low有効
hwriteI1書き込み有効
htransI2現在の転送タイプ
hsizeI3現在の転送サイズ
haddrI32読み書きアドレス
hburstI3現在のバーストタイプ
hwdataI32書き込みデータ
hreadyO1転送完了指示
hrespO2転送応答
hrdataO32読み出しデータ
sram_csnO1SRAMチップ選択、Low有効
sram_wenO1SRAM書き込みイネーブル、Low有効
sram_addrO12SRAM読み書きアドレス
sram_dinO32SRAM書き込みデータ
sram_doutI32SRAM読み出しデータ

設計要件:

  • Verilog実装コードは合成可能であること
  • シミュレーションでは、様々な典型的な状況下でのデータ読み書きインターフェース信号波形を示すこと
設計アプローチ:

CPUのメモリアクセスはバイト(8ビット)単位で行われるため、メモリのデータ幅とバス幅が32ビットで揃っている場合、アクセスアドレスのシフトを考慮する必要があります。32ビットアクセスの場合はhaddrを2ビット左シフトし、16ビットアクセスの場合は1ビット左シフトし、8ビットアクセスの場合はシフト不要です。

コード実装:
module ahb_sram_controller (
    input hclk,
    input hresetn,
    input hwrite,
    input [1:0] htrans,
    input [2:0] hsize,
    input [31:0] haddr,
    input [2:0] hburst,
    input [31:0] hwdata,
    output reg hready,
    output reg [1:0] hresp,
    output reg [31:0] hrdata,
    output reg sram_csn,
    output reg sram_wen,
    output reg [11:0] sram_addr,
    output reg [31:0] sram_din,
    input [31:0] sram_dout
);

    reg [31:0] write_mask;

    always @(posedge hclk or negedge hresetn) begin
        if(hresetn == 1'b0) begin
            write_mask <= 0;
            hready <= 1'b1;
            hresp <= 2'b0;
            hrdata <= 0;
            sram_csn <= 1'b0;
            sram_wen <= 1'b0;
            sram_addr <= 0;
            sram_din <= 0;
        end
        else begin
            sram_wen <= hwrite & htrans[1];
            sram_addr <= haddr[13:2];
        end
    end

    always @(posedge hclk or negedge hresetn) begin
         if(hresetn == 1'b0) begin
            hrdata <= 0;
            sram_din <= 0;
        end
        else begin
            case (hsize[1:0])
                2'b10: write_mask <=  32'hFFFFFFFF;                        // ワード書き込み
                2'b01: write_mask <= (32'h0000FFFF << (16 * haddr[1]));    // ハーフワード書き込み
                2'b00: write_mask <= (32'h000000FF << (8 * haddr[1:0]));   // バイト書き込み
                default: write_mask <= 32'hFFFFFFFF;            
            endcase
            sram_din <= (hwdata & write_mask) | (hrdata & ~write_mask);
            hrdata <= sram_dout;
        end
    end

endmodule
SRAMモデル:
module sram_model #(
    parameter ADDR_WIDTH = 12,
    parameter DATA_WIDTH = 32,
    parameter MEMORY_SIZE = 4096
)(
    input clk,
    input rst_n,
    input cs_n,
    input we_n,
    input [ADDR_WIDTH-1:0] addr,
    input [DATA_WIDTH-1:0] din,
    output reg [DATA_WIDTH-1:0] dout
);
    
    reg [DATA_WIDTH-1:0] memory [MEMORY_SIZE-1:0];
    integer i;

    always @(posedge clk or negedge rst_n) begin
        if (rst_n == 1'b0) begin
            for (i = 0; i < MEMORY_SIZE; i=i+1) begin
                memory[i] <= 0;
            end
        end
        else if (we_n == 1'b1 && cs_n == 1'b0) begin
            memory[addr] <= din;
        end
    end

    always @(posedge clk or negedge rst_n) begin
        if (rst_n == 1'b0) begin
            dout <= 0;
        end
        else if (cs_n == 1'b0) begin
            dout <= memory[addr];
        end
    end

endmodule
テストベンチ:
module ahb_sram_testbench ();
    
    reg hclk;
    reg hresetn;
    reg hwrite;
    reg [1:0] htrans;
    reg [2:0] hsize;
    reg [31:0] haddr;
    reg [2:0] hburst;
    reg [31:0] hwdata;
    wire hready;
    wire [1:0] hresp;
    wire [31:0] hrdata;
    wire sram_csn;
    wire sram_wen;
    wire [11:0] sram_addr;
    wire [31:0] sram_din;
    wire [31:0] sram_dout;

    initial begin
        hclk <= 1'b0;
        hresetn <= 1'b0;
        hwrite <= 1'b0;
        htrans <= 2'b00;
        hsize <= 3'b000;
        haddr <= 32'h00000000;
        hburst <= 3'b000;
        hwdata <= 32'h00000000;
        #20
        hresetn <= 1'b1;
        hwrite <= 1'b1;
        htrans <= 2'b10;
        hsize <= 3'b010;
        #20
        haddr <= 32'hfffffffc;
        hwdata <= 32'h20211212;
        #20
        hsize <= 3'b001;
        haddr <= 32'hfffffffE;
        hwdata <= 32'habcd0000;
        #20
        hsize <= 3'b000;
        haddr <= 32'hffffffff;
        hwdata <= 32'h59000000;
        #20
        hwrite <= 1'b0;
    end

    always #10 hclk <= ~hclk;

    ahb_sram_controller u_ahb_sram_ctrl(
        .hclk(hclk),
        .hresetn(hresetn),
        .hwrite(hwrite),
        .htrans(htrans),
        .hsize(hsize),
        .haddr(haddr),
        .hburst(hburst),
        .hwdata(hwdata),
        .hready(hready),
        .hresp(hresp),
        .hrdata(hrdata),
        .sram_csn(sram_csn),
        .sram_wen(sram_wen),
        .sram_addr(sram_addr),
        .sram_din(sram_din),
        .sram_dout(sram_dout)
    );

    sram_model #(
        .ADDR_WIDTH(12),
        .DATA_WIDTH(32),
        .MEMORY_SIZE(4096)
    ) u_sram (
        .clk(hclk),
        .rst_n(hresetn),
        .cs_n(sram_csn),
        .we_n(sram_wen),
        .addr(sram_addr),
        .din(sram_din),
        .dout(sram_dout)
    );

endmodule

タグ: Verilog デジタル回路設計 順序論理 メモリ AHBバス

6月18日 23:06 投稿