次はちょっと本格的に論理回路をシミュレーションしてみます。
サンプルの論理回路は次のように作成しました。
`default_nettype none
`timescale 1ns / 1ps
module test1
(
input wire RST_N,
input wire CLK,
input wire START,
input wire STOP,
output [7:0] COUNT
);
reg [7:0] reg_count;
reg reg_exec;
always @(posedge CLK or negedge RST_N) begin
if(!RST_N) begin
reg_exec <= 0;
end else begin
if(START) begin
reg_exec <= 1;
end else if(STOP) begin
reg_exec <= 0;
end
end
end
always @(posedge CLK or negedge RST_N) begin
if(!RST_N) begin
reg_count <= 0;
end else begin
if(reg_exec) reg_count <= reg_count +1;
end
end
assign COUNT = reg_count;
endmodule
`default_nettype none
次のような動作をする簡単な回路です。
START
に1
が入力されるとreg_exec
が1
になって、STOP
に1
が入力されるとreg_exec
が0
になりますreg_exec
が1
ならreg_count
がインクリメントしますreg_count
をCOUNT
に出力しますテストベンチは次のように作成しました。
#include "verilated.h"
#include "verilated_vcd_c.h"
#include "Vtest1.h"
#define CSCALE (10)
unsigned int mtime = 0; // current simulation time
int main (int argc, char **argv)
{
Verilated::commandArgs(argc, argv);
Vtest1* top = new Vtest1;
Verilated::traceEverOn(true);
VerilatedVcdC* tfp = new VerilatedVcdC;
top->trace (tfp, 99);
tfp->open ("sim_test1.vcd");
top->RST_N = 0;
top->CLK = 0;
top->START = 0;
top->STOP = 0;
int mcycle = 0;
while(!Verilated::gotFinish()){
if((mtime % (CSCALE/2)) == 0) top->CLK = !top->CLK; // create clock
if((mtime % CSCALE) == 0) mcycle++;
if(mcycle > 10) top->RST_N = 1; // release reset
if(mcycle > 20) top->START = 1; // active for START
if(mcycle > 30) top->START = 0; // de-active for START
if(mcycle > 160) top->STOP = 1; // active for START
if(mcycle > 170) top->STOP = 0; // de-active for START
top->eval(); // eval
tfp->dump(mtime);
if((mtime % CSCALE) == 0) {
printf("Time %d: RST_N = %d, CLK = %d, START = %d, STOP = %d, COUNT = %d, reg_exec = %d\n", mtime, top->RST_N, top->CLK, top->START, top->STOP, top->COUNT, top->test1__DOT__reg_exec);
}
if(mcycle > 200) break;
mtime++;
}
tfp->close();
top->final();
delete top;
exit(0);
}
この回路のクロックはCLK
で動作周波数はif((mtime % (CSCALE/2)) == 0) top->CLK = !top->CLK;
で作成しています。
CSACLE
は#define CSCALE (10)
でwhile(!Verilated::gotFinish())
内のmtime
で計算しているのでmtime
の5回に1回、CLKがトグルします。
mcycle
をCSACLE
でインクリメントしているのでCLKの何クロック目
のようなカウンタにしています。
RST
、START
、STOP
はmcycle
に合わせて値を設定しています。
START
は次のように記載しているのでmcycle
の21〜30の間、1
にします。
if(mcycle > 20) top->START = 1; // active for START
if(mcycle > 30) top->START = 0; // de-active for START
テストベンチは単にC言語で実行されるのでシーケンシャル処理です。
つまり、mcycle
が40のときのSTART
はmcycle > 20
で一度、1
になってからmcycle > 30
で0
になります。
そして、top->eval();
の部分でシミュレーションが評価されます。
tfp->dump(mtime);
のところで信号がダウンプされます。
次のようにコンパイルと実行してみましょう。
$ verilator -Wall --trace --cc test1.v --exe sim_test1.cpp
$ cd obj_dir/
$ make -f Vtest1.mk Vtest1
$ ./Vtest1
実行が完了するとメッセージとともにsim_test1.vcd
ができています。
これは信号の波形です。
sim_test1.vcd
は次のようにgtkwave
で波形を見ることができます。
$ gtkwave sim_test1.vcd
Tweet
write: 2020/06/28/ 04:00:00