
前回はバイナリカウンタでしたが、今回は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。大丈夫か?





