帰らざるMOS回路(26) ROMファイルをVerilogHDLとLogisimで共用する

Joseph Halfmoon

前回はバイナリカウンタでしたが、今回はROMです。ROMは複数の用途に使うことを想定。ROMに記録すべきビットパターンは外部の「ROMファイル」に書いておいて必要に応じてファイルを切り替えて「ロード」するようにしたいです。またそのファイルはゲートレベルのLogisimとVerilogHDLで共用できるのが望ましいです。

※使用させていただいとります「フリー」ツールのホームページへのリンクは以下です。

Logisim 画面上でゲートレベルの論理回路の動作を観察できるツール。左記からダウンロードして実行可能。しかし既に “suspended indefinitely” 状態。

Icarus Verilog 「商用でない」Verilogの定番。

GTKWave Verilog処理系などが出力する VCDフォーマットのファイルをタイミングチャートとしてみるためのビューワー

ROMの用途2つ

現状想定しているROMの用途は以下の2つです。

    1. 普通にROMとして回路の一部に組み込む。ROM搭載のマイコンのROMのようなイメージ。
    2. 外部からシミュレーションパターンを読み取る手段のないLogisimにシミュレーションテストベンチ用の入力スティミュラス生成器として使う

片やターゲット回路の一部であり、片やテストベンチ(実回路にはならない仮想的なもの)の一部なので使用時には扱いが異なるでしょう。しかし今回はその準備なのでとりあえず「一緒」であります。また、よほど規模が小さいROM以外は論理合成することは無いと思われるので、ハードに組み込む場合も専用セルのROMアレイを想定。

Logisim上でのROM

以下にLogisimのライブラリで用意されているROMを示します。特に読み書きのための制御信号はなく非常に単純、メモリではありますがタイミング的には組み合わせ回路です。唯一チップセレクト的なSEL信号がありますが接続しなければ常に選択されるという仕様です。

    • アドレス線(最大24ビット)
    • データ線(最大32ビット)
    • セレクト信号

ROM_LOGIC

ROM内のビットパターンは、以下のエディタを呼び出して手動で入力することもできますが、外部のテキストファイルから読み込むのが良かろうかと思います。ROM_LOGIC_EDITOR

読み込めるテキストファイルの例が以下に。8ビット幅の場合です。ベタなHEX形式。先頭にファイル形式のバージョンを示すらしい行があるのがイマイチ。

ROMtxt_LOGIC

 

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のファイルと共用できます。

ROMhex_verilog

 

実行結果

以下は icarus Verilog でエラボレーションして、実行しているコマンド行です。

$ iverilog -o tb.out testBench.v counter5.v rom8.v
$ vvp tb.out

標準出力上の$monitorの結果の一部が以下に。ダラダラとROMの内容が0番地から順に出力されております。

ROMdump

いつものように、出力されたVCDファイルをgtkWaveでタイミングチャートとして眺めたものが以下です。

gtkwaveROM

ROMもOK。大丈夫か?

帰らざるMOS回路(25)今時ゲートレベルでもあるまいに。カウンタをVerilogしてみる へ戻る

帰らざるMOS回路(27) Icarus Verilog小ネタ、ライブラリ、実行時パラメータ へ進む