前回はバイナリカウンタでしたが、今回はROMです。ROMは複数の用途に使うことを想定。ROMに記録すべきビットパターンは外部の「ROMファイル」に書いておいて必要に応じてファイルを切り替えて「ロード」するようにしたいです。またそのファイルはゲートレベルのLogisimとVerilogHDLで共用できるのが望ましいです。
※かえらざるMOS回路 投稿順 INDEX
※使用させていただいとります「フリー」ツールのホームページへのリンクは以下です。
Logisim 画面上でゲートレベルの論理回路の動作を観察できるツール。左記からダウンロードして実行可能。しかし既に “suspended indefinitely” 状態。
Icarus Verilog 「商用でない」Verilogの定番。
GTKWave Verilog処理系などが出力する VCDフォーマットのファイルをタイミングチャートとしてみるためのビューワー
ROMの用途2つ
現状想定しているROMの用途は以下の2つです。
-
- 普通にROMとして回路の一部に組み込む。ROM搭載のマイコンのROMのようなイメージ。
- 外部からシミュレーションパターンを読み取る手段のないLogisimにシミュレーションテストベンチ用の入力スティミュラス生成器として使う
片やターゲット回路の一部であり、片やテストベンチ(実回路にはならない仮想的なもの)の一部なので使用時には扱いが異なるでしょう。しかし今回はその準備なのでとりあえず「一緒」であります。また、よほど規模が小さいROM以外は論理合成することは無いと思われるので、ハードに組み込む場合も専用セルのROMアレイを想定。
Logisim上でのROM
以下にLogisimのライブラリで用意されているROMを示します。特に読み書きのための制御信号はなく非常に単純、メモリではありますがタイミング的には組み合わせ回路です。唯一チップセレクト的なSEL信号がありますが接続しなければ常に選択されるという仕様です。
-
- アドレス線(最大24ビット)
- データ線(最大32ビット)
- セレクト信号
ROM内のビットパターンは、以下のエディタを呼び出して手動で入力することもできますが、外部のテキストファイルから読み込むのが良かろうかと思います。
読み込めるテキストファイルの例が以下に。8ビット幅の場合です。ベタなHEX形式。先頭にファイル形式のバージョンを示すらしい行があるのがイマイチ。
VerilogでのROM記述
さて、Verilogで上記のようなタイミングの無い、組み合わせ回路として扱えるROMを書いてみたものが以下です。ROMのビットパターンを外部ファイルから読み取るために $readmemhしてます。当然こういうモジュールは論理合成不可でしょうな。
/** @file 8bit x 32 word ROM */ `ifndef ROM8_V_ `define ROM8_V_ /** The ROM8 module @param[in] ADDR [4:0] address input @param[out] DAT [7:0] data output */ module rom8( ADDR, DAT ); input [4:0] ADDR; output [7:0] DAT; reg [7:0] mem [0:31]; initial $readmemh("ROM.hex", mem); assign DAT = mem[ADDR]; endmodule `endif // rom8_V_
Verilogテストベンチ
上記の「組み合わせ回路ROM」をテストのため「舐める」ためのテストベンチが以下です。前回の8ビット・バイナリ・カウンタを流用した5ビットのバイナリカウンタでROMアドレスをなめてます。
/** @file testBench.v, to test rom8.v (8 bit x 32 word ROM) */ `ifndef TESTBENCH_V_ `define TESTBENCH_V_ `timescale 1 us / 100 ns /** The rom8 testbench */ module rom8_tb; reg CLK, RST; wire [4:0] ADR; wire [7:0] DAT; parameter STEP = 10; counter5 address( CLK, RST, ADR ); rom8 dut ( ADR, DAT ); initial begin $dumpfile("ROM8.vcd"); $dumpvars(-1, dut); $monitor("%d OUT=%d", $stime, DAT); end // testbench actions always begin CLK=0; #(STEP/2); CLK=1; #(STEP/2); end initial begin #0 RST = 1'b1; #STEP RST = 1'b0; #(STEP*33) $finish; end endmodule `endif // TESTBENCH_V_
テストベンチで使ったアドレスカウンタのコードは前回のチョイ直しで流用。
/** @file 5bit binary counter */ `ifndef COUNTER5_V_ `define COUNTER5_V_ /** The COUNTER5 module @param[in] CLK clock input @param[in] RST reset input @param[out] OUT [4:0] counter output */ module counter5( CLK, RST, OUT ); input CLK, RST; output [4:0] OUT; reg [4:0] OUT; always @( posedge CLK or posedge RST) begin if ( RST==1'b1 ) OUT <= 5'h00; else OUT <= OUT + 5'h01; end endmodule `endif // COUNTER5_V_
肝心のROMファイルの例が以下に。HEXのテキストファイルです。先頭の1行を除けばLogisimと同じものです。頭の1行を切り取るか、コメント文字を挿入するかすればLogisimのファイルと共用できます。
実行結果
以下は icarus Verilog でエラボレーションして、実行しているコマンド行です。
$ iverilog -o tb.out testBench.v counter5.v rom8.v $ vvp tb.out
標準出力上の$monitorの結果の一部が以下に。ダラダラとROMの内容が0番地から順に出力されております。
いつものように、出力されたVCDファイルをgtkWaveでタイミングチャートとして眺めたものが以下です。
ROMもOK。大丈夫か?