工業製造
産業用モノのインターネット | 工業材料 | 機器のメンテナンスと修理 | 産業プログラミング |
home  MfgRobots >> 工業製造 >  >> Industrial programming >> Verilog

VerilogシングルポートRAM設計:同期読み書きの完全ガイド

シングルポート同期RAMの設計

同期RAMは、クロックエッジで読み書き両方を制御するメモリです。アドレス幅ADDR_WIDTH、データ幅DATA_WIDTH、深さDEPTHをパラメータ化し、汎用的に使えます。入出力は双方向バスdata(inout)で、チップセレクトcs、書き込みイネーブルwe、出力イネーブルoeで制御します。

module single_port_sync_ram #(
  parameter ADDR_WIDTH = 4,
  parameter DATA_WIDTH = 32,
  parameter DEPTH = 16
)(
  input  clk,
  input  [ADDR_WIDTH-1:0] addr,
  inout  [DATA_WIDTH-1:0] data,
  input  cs,      // チップセレクト
  input  we,      // 書き込みイネーブル(Highで書き込み)
  input  oe       // 出力イネーブル(Highで出力)
);
  reg [DATA_WIDTH-1:0] tmp_data;      // 読み出しデータ保持用
  reg [DATA_WIDTH-1:0] mem [DEPTH];   // メモリ本体

  // 同期書き込み:クロック立ち上がりで cs & we なら書き込み
  always @(posedge clk) begin
    if (cs & we)
      mem[addr] <= data;
  end

  // 同期読み出し:クロック立ち上がりで cs & !we なら読み出し
  always @(posedge clk) begin
    if (cs & !we)
      tmp_data <= mem[addr];
  end

  // 双方向バス制御:cs & oe & !we なら tmp_data を駆動、 else Hi-Z
  assign data = (cs & oe & !we) ? tmp_data : 'hz;
endmodule

重要な設計ポイント

回路図

テストベンチ

全アドレス(0〜15)へ書き込み、次に全アドレスから読み出しを行います。

module tb;
  parameter ADDR_WIDTH = 4;
  parameter DATA_WIDTH = 16;
  parameter DEPTH = 16;

  reg clk;
  reg cs, we, oe;
  reg [ADDR_WIDTH-1:0] addr;
  wire [DATA_WIDTH-1:0] data;
  reg [DATA_WIDTH-1:0] tb_data;

  single_port_sync_ram #(.DATA_WIDTH(DATA_WIDTH)) u0 (
    .clk(clk), .addr(addr), .data(data),
    .cs(cs), .we(we), .oe(oe)
  );

  always #10 clk = ~clk;  // 20ns周期

  // TB側からデータバス駆動:oe=0時にtb_dataを出力
  assign data = !oe ? tb_data : 'hz;

  initial begin
    {clk, cs, we, addr, tb_data, oe} <= 0;
    repeat (2) @(posedge clk);

    // 書き込みフェーズ:全アドレスへランダムデータ書き込み
    for (integer i = 0; i < 2**ADDR_WIDTH; i = i + 1) begin
      repeat (1) @(posedge clk);
      addr <= i;
      we <= 1; cs <= 1; oe <= 0;
      tb_data <= $random;
    end

    // 読み出しフェーズ:全アドレスから読み出し
    for (integer i = 0; i < 2**ADDR_WIDTH; i = i + 1) begin
      repeat (1) @(posedge clk);
      addr <= i;
      we <= 0; cs <= 1; oe <= 1;
    end

    #20 $finish;
  end
endmodule

動作タイミング

クロック:  ___/‾\___/‾\___/‾\___
書き込み:     ▲       ▲
              addr=0    addr=1    data駆動(tb_data)
読み出し:           ▲       ▲
                    addr=0    addr=1    data出力(tmp_data)  ← 1クロック遅延

実用上の考慮事項

SystemVerilogでのモダンな書き方

module single_port_sync_ram #(
  parameter int ADDR_WIDTH = 4,
  parameter int DATA_WIDTH = 32,
  parameter int DEPTH = 16
)(
  input  logic clk,
  input  logic [ADDR_WIDTH-1:0] addr,
  inout  wire [DATA_WIDTH-1:0] data,
  input  logic cs, we, oe
);
  logic [DATA_WIDTH-1:0] mem [DEPTH];
  logic [DATA_WIDTH-1:0] tmp_data;
  logic                  data_oe;

  always_ff @(posedge clk) begin
    if (cs && we) mem[addr] <= data;
    if (cs && !we) tmp_data <= mem[addr];
  end

  assign data_oe = cs && oe && !we;
  assign data = data_oe ? tmp_data : 'z;
endmodule

Verilog

  1. Verilogマスター:デジタル回路設計のための完全チュートリアル
  2. Verilog連結マスター:実践ガイド
  3. Verilog代入文の理解:種類、構文、ベストプラクティス
  4. Verilogブロッキング代入とノンブロッキング代入:違いを徹底解説
  5. Verilog関数のマスター:効率的なRTL設計のために
  6. Verilogタスクの理解:関数との違い、構文、使用法
  7. Verilogクロックジェネレータ:設計と実装ガイド
  8. Verilog数学関数のマスター:効率的なハードウェア設計のために
  9. Verilog $timeformatのマスター:精度と表示制御
  10. 任意のスコープでのVerilog timescale理解と表示
  11. VerilogファイルI/Oの完全ガイド:オープン、読み取り、書き込み、クローズ
項目考慮点
FPGAブロックRAM合成ツールが自動的にブロックRAM(BRAM)にマッピング。パラメータでサイズ指定
初期化$readmemh/$readmembでHEX/BINファイルから初期化可能
非同期読み出しalways @(*) tmp_data = mem[addr]で0遅延読み出し可能(タイミング注意)
バイトイネーブル部分書き込み対応ならinput [DATA_WIDTH/8-1:0] be追加
出力レジスタタイミング改善のため出力側にレジスタ段追加(reg [DATA_WIDTH-1:0] data_out)も常套