前言
如果对verilog FPGA及其Linux系统上的使用的相关知识有疑问可以参照:https://www.kancloud.cn/dlover/fpga/1251121
本人仿真环境: iverilog + gtkwave
2020年了,似乎去官网上下载modelsim只能下载student版本的,关键是还没有linux版本的,在eetop找的资源安装,都失败了。只好选择iverilog + gtkwave 了。
安装链接即步骤看链接:https://blog.youkuaiyun.com/zoomdy/article/details/79525870
链接中执行一次需要输入四行命令:
$:iverilog -o counter_test counter_tb.v counter.v
$:vvp -n counter_test -lxt2
$:cp counter_test.vcd counter_test.lxt
$:gtkwave counter_test.lxt
作为一个懒人,忍受不了,所以简单包装了一下,其中参数“gtk可选”:
bash iv.sh counter_tb.v counter.v
或者
bash iv.sh counter_tb.v counter.v gtk
#grep --exclude Defines.h Truthtable.h *
#!/usr/bin/env bash
#SELFDIR=$(dirname $(realpath "$BASH_SOURCE"))
SELFDIR=$(cd $(dirname "$BASH_SOURCE");pwd)
if [[ ${SELFDIR} == "" ]]; then
echo "Internal error: can not locate the script dir"
exit 1
fi
echo $1
if [ "$1" == "" ]
then
echo "Parameter Fail"
echo " eg:bash iv.sh counter_tb.v counter.v"
exit 1
elif [ "$2" == "" ]
then
echo "Parameter Fail"
echo " eg:bash iv.sh counter_tb.v counter.v"
exit 1
else
echo "Parameter OK "
iverilog -o counter_test $1 $2
vvp -n counter_test -lxt2
cp counter_test.vcd counter_test.lxt
fi
if [ "$3" == "gtk" ]
then
gtkwave counter_test.lxt
fi
需要注意的是,这里的counter_test是因为之前的testbench里有对应的语句:
$dumpfile("counter_test.vcd");
$dumpvars(0,counter_test; 要记录的信号,level=0表示记录所有
它们表示记录对应的变量并保存,其中参数0表示记录所有变量。
initial begin
num=6;
power = 2;
rst = 1;
#100;
rst = 0;
#100000;
$finish;
end
坑1:testbench的顺序
在同步时序逻辑中,input的变量最好在rst复位之前声明如下:
initial begin
num=6;
power = 2;
rst = 1;
#100;
rst = 0;
#10000
$finish;
end
如果写成这样:
initial begin
rst = 1;
#100;
rst = 0;
num=6;
power = 2;
#10000
$finish;
end
看着也没什么毛病,但是本人仿真了一个晚上,跑出的波形,受影响的变量显示为X,也就是不定态。
坑2.verilog文件读写
module read_write_file();
integer fp_r,fp_w;
integer count;
reg [13:0] reg1;
reg [13:0] reg2;
reg [20:0] reg3;
initial
begin
fp_r=$fopen("fntt.txt","r");//以读的方式打开文件
fp_w=$fopen("data_out.txt","w");//以写的方式打开文件
while(! $feof(fp_r))
begin
count=$fscanf(fp_r,"%d%d%d" ,reg1,reg2,reg3) ;//每次读一行
$display("%d",reg1) ;//打印输出
$fwrite(fp_w,"%d\t%d\t%d\n",reg1,reg2,reg3) ;//写入文件
end
$fclose(fp_r);//关闭已打开的文件
$fclose(fp_w);
end
endmodule
- 注意这里与原链接中的代码略有不同,这里是一行读取三个数据,比如一行有三个数据,中间用“\t”隔开,就可以这样读取。
- 经本人踩坑,对于一行有三个数据,但是我只想读取其中的两个数据,还是要
count=$fscanf(fp_r,"%d%d%d" ,reg1,reg2,reg3) ;//每次读一行
三个都写上,处理的时候只处理两个就行了,倘若不三个一起读,而是改为count=$fscanf(fp_r,"%d%d" ,reg1,reg2) ;//每次读一行
则读出的数据是错的。
坑3.@(negedge Clk)(没有always时)
代表等待一个下降沿?
http://forum.eepw.com.cn/thread/251730/1/
坑4.begin后的冒号?
begin:shift
XXXXXXXXXX
end
begin后面有个冒号代表对这个begin–end起个名字,没什么特殊含义
坑5.操作二维数组?
http://www.voidcn.com/article/p-thkupwlb-btg.html
转换成一维向量传输
读取ROM:http://cn.voidcc.com/question/p-znsrhazp-or.html
读ROM+写ROM:http://www.voidcn.com/article/p-chjjifpy-btx.html:$writememh $readmemh
坑六.case语句
原文:https://blog.youkuaiyun.com/fadbgfnbxb/article/details/89813526
case语句中有两种状态对就同一个电路?用逗号分开即可
reg [1:0]addr_cnt=2'b11;
reg read=1'b1;
always@(posedge clk_40M) begin
addr_cnt <= addr_cnt + 1'b1;
case(addr_cnt)
2'b00,2'b01: read <= 1'b0;//对某变量完全相同的操作,逗号隔开不同的分支
2'b10: read <= 1'b1;
2'b11: read <= 1'bz;//一个分支仅对一个变量赋值时,可以不用begin end
default: ; //直接分号 等价于进行" read <= read;"操作
endcase;
end
1.Verilog描述
reg[7:0] mema[0:255] ; 声明一个数组mema为256*8bits寄存器,其索引为0~255,宽度为8
reg arrayb [7:0] [0:255]; 声明一个二维数组,其数据为1位寄存器
time hist[1:1000]; 有1000个时间值的数组
reg [1:n] rega; 一个n位的1个深度的寄存器(存储器)
reg mema [1:n]; 一个1位的n个深度的寄存器(存储器)
2.操作符
== :逻辑相等
=== :条件(case)相等
!== :条件(case)不相等
~| :规约或非
<< :逻辑左移
<<< :算术左移
a**b :a的b次幂
3.延时
对门延时来讲
min:typical:maximum 最小值:典型值:最大值
eg:
#(95:100:105) clk = 1;
4.assign && deassign
摘自:https://www.eefocus.com/xiaxing_fpga/blog/11-08/230004_7058d.html
assign用于对寄存器赋值(不可用于线网赋值),deassign用于取消之前由assign赋值给某寄存器的值,也就是说,使用assign给寄存器赋值之后,这个值将一直保持在这个寄存器上,直到遇到deassign为止。
module DEF(D,Clr,Clk,Q)
input D,Clr,Clk;
output Q;
reg Q;
always@(negedge Clk)
Q = D;
always@(Clr)
begin
if(!Clr)
assign Q = 0;
else
deassign Q;
end
endmodule
以上的程序段,第一个always会将Q的值赋为D,第二个always语句在Clr的值发生变化时执行,若Clr是由高电平变为低电平,则assign有效,并一直保持这个赋值(直到遇到deassign),这时尽管第一个always也在执行(Clk的下降沿是不会起作用的),Q的值会一直保持“assign Q = 0;”,直到Clr来一个高电平为止(deassign Q语句执行)。
force-release(强制-释放,虽然它也可以用于对寄存器赋值,但主要用于线网赋值)
当force语句应用于寄存器时,寄存器当前值被force覆盖,当release语句应用于寄存器时寄存器当前值将保持不变,直到被重新赋值。
5.wait
摘自:https://www.cnblogs.com/ostien/p/3640816.html
Wait(var)
begin
expression1;
expression2;
.....
end
other_expression; //后续代码
当avr为真(非0)时,程序执行begin-end块里面的代码,然后继续执行other_expression代码。然而,当avr为假(0,x,z)时,程序暂停,一直等待avr变成真之后再继续执行,该语句不可以综合。可以像下面一样写代码:
6.fork ----join
fork -join结构之间的语句都是并发执行的
//下面这段语句将产生竞争条件
fork
#5 a=b;
#5 b=a;
join
//下面这段语句消除了竞争条件
//功能:数据交换
fork
a=#5b;
b=#5a;
join
//下面这段语句将产生竞争条件
//功能:数据移位
fork
a=@(posedge clk) b;
b=@(posedge clk) a;
join