“本文主要分享了在Verilog设计过程中一些经验与知识点,主要包括Verilog仿真时常用的系统任务、双向端口的使用(inout)、边沿检测”
01
—
仿真时常用的系统任务($display,$fopen,$fscanf,$fwrite($fdisplay),$fclose,$random,$stop)
在RTL设计过程中,仿真的时候需要用一些系统函数,这边笔整理了部分Verilog设计中常用的系统函数:$display,$fopen,$fscanf,$fwrite($fdisplay),$fclose,$random,$stop。
-
$display
这个函数系统任务的作用是用来在控制台输出信息。
-
$display("!!! Start Simulation !!!");直接显示字符串
-
$display("data_display = %h hex %d decimal",100, 100); //显示data_display 的16进制 ,10进制
-
$display("data_display = %o otal %b binary",100, 100);//显示data_display 的8进制 2进制
-
$display("data_display = %d otal next line %bbinary", 100, 100);//主要展示换行操作
-
$display("simulation time is %t",$time);//显示系统仿真时间
具体代码如下:
regflag;
//****************************** 系统显示 $display *******************************
reg[31:0]data_display;
initial
begin
data_display = 32'd100;
flag = 0;
$display("!!! Start Simulation !!!");
//显示16进制 10进制
$display("data_display = %h hex %d decimal", 100, 100);
//显示8进制 2进制
$display("data_display = %o otal %b binary", 100, 100);
//ASCII码
$display("data_display has %c ascii character value",64);
//显示10进制 换行 2进制
$display("data_display = %d otal next line %b binary", 100, 100);
//显示系统仿真时间
$display("simulation time is %t",$time);
flag = 1;
end
仿真结果如下图所示:
在第五行展示了换行功能;为了验证系统仿真时间,笔者这边用flag参数拉高来测试时间,时间结果如下图显示,和显示时间一致;
-
$fopen
-
$fscanf
//****************************** 读文件 $fscanf *******************************
//宏定义,定义数据长度
`define DATA_LENGTH 8
//定义RAM大小
reg signed [15:0] Sig0 [`DATA_LENGTH-1:0];
reg [15:0]Sig1[`DATA_LENGTH-1:0];
//定义句柄
integer data_file0;
integerdata_file1;
integeri;
//读取函数
initial
begin
#200;
//打开句柄
data_file0 = $fopen("file/rd_data0_fpga.txt","r");
data_file1 = $fopen("file/rd_data1_fpga.txt","r");
for(i = 0;i < `DATA_LENGTH; i = i + 1)
begin
$fscanf(data_file0,"%d",Sig0[i]); //读取十进制
$fscanf(data_file1,"%h",Sig1[i]); //读取十六进制
end
$fclose(data_file0); ////关闭这个句柄
$fclose(data_file1); ////关闭这个句柄
end
仿真结果如下图所示:
-
$fwrite($fdisplay)
代码如下所示:
仿真结果如下所示//************************** 写文件 $fwrite($fdisplay) *************************
//****** $fwrite 写下一个数不会自动转行,所以要加
//将读取的Sig0,Sig1重新写进两个新的txt中
//定义句柄
integer data_wr0;
integer data_wr1;
integer m;
//读取函数
initial
begin
#400;
//打开句柄
data_wr0 = $fopen("file/wr_data1_fpga.txt","w");
data_wr1=$fopen("file/wr_data2_fpga.txt","w");
for(m = 0;m < `DATA_LENGTH; m = m + 1)
begin
@(clk);
$fwrite(data_wr0,"%d ",Sig0[m]); //向txt写十进制 写下一个数不会自动转行,所以要加
$fwrite(data_wr1,"%h ",Sig1[m]); //向txt写十六进制 写下一个数不会自动转行,所以要加
end
//关闭这个句柄
$fclose(data_wr0);
$fclose(data_wr1);
end
$fwrite和$fdisplay的区别,$fwrite写下一个数不会自动转行,可以加 来转行,$fdisplay则会自动转行。
-
$fdisplay
仿真结果如下图所示://****** $fdisplay
//将读取的Sig0,Sig1重新写进两个新的txt中
//定义句柄
integer data_wr2;
integer data_wr3;
integer j;
//读取函数
initial
begin
#600;
//打开句柄
data_wr2 = $fopen("file/wr_data3_fpga.txt","w");
data_wr3=$fopen("file/wr_data4_fpga.txt","w");
for(j = 0;j < `DATA_LENGTH; j = j + 1)
begin
@(clk);
$fdisplay(data_wr2,"%d",Sig0[j]); //向txt写十进制 写下一个数会自动转行,所以不需要加
$fdisplay(data_wr3,"%h",Sig1[j]); //向txt写十六进制 写下一个数会自动转行,所以不需要加
end
//关闭这个句柄
$fclose(data_wr2);
$fclose(data_wr3);
end
-
$fclose
-
$stop
02
—
双向端口的使用(inout)
根据Verilog的语法定义,IO的端口可以定义为三种类型input、output和inout,其中inout为双向端口。双向端口通过控制三态门来实现,其结构框图如下所示。
-
当T为1的时候,I端忽略(高阻),O端电平 = IO端电平;
-
当T为0的时候,IO端电平=I端电平=O端电平;
实现代码如下:
同样,Xilinx也有三态门的源语assign io = ( !t ) ? i : 1'bz ;
assign o = io;
参考:Xilinx 7 Series FPGA Libraries Guide for HDL Design
仿真结果如下:IOBUF
.DRIVE ( 12 ), // Specify the output drive strength
.IBUF_LOW_PWR ( "TRUE" ), // Low Power - "TRUE", High Performance = "FALSE"
.IOSTANDARD ( "DEFAULT" ), // Specify the I/O standard
.SLEW ( "SLOW" ) // Specify the output slew rate
) IOBUF_inst (
.O(o1 ),//Bufferoutput
.IO(io),//Bufferinoutport(connectdirectlytotop-levelport)
.I(i1),//Bufferinput
.T ( t ) // 3-state enable input, high=input, low=output
);
可以看出:
-
当T=1的时候,O端电平=IO端电平;
-
当T=0的时候,O端电平=IO端电平=I端电平。
03
—
边沿检测
在程序设计过程中,经常需要检测一个脉冲信号的上升沿或者下降沿,下面给大家介绍如何使用Verilog实现对脉冲信号的边沿进行检测。时钟信号与脉冲信号如下图所示。
Verilog代码如下:
上述程序经过综合后,其RTL结构如下图所示,由两个D触发器和两个与门组成。module edge_detection(
input wire clk,
input wire rst,
input wire sin_pulse,
output wire sout_r, //上升沿检测
output wire sout_f //下降沿检测
);
//--------------------------------------------------------------------------------
reg sin_reg0,sin_reg1;
//--------------------------------------------------------------------------------
clk or posedge rst)
begin
if(rst)
begin
sin_reg0 <= 0;
sin_reg1 <= 0;
end
else
begin
sin_reg0 <= sin_pulse;
sin_reg1 <= sin_reg0;
end
end
//--------------------------------------------------------------------------------
assign sout_r = sin_reg0 & (~sin_reg1); //上升沿检测
(~sin_reg0)&sin_reg1;//下降沿检测 =
//--------------------------------------------------------------------------------
仿真后的结果如下图所示,可以看出sout_r为上升沿检测结果,sout_f为下降沿检测结果。
审核编辑:郭婷
-
Verilog
+关注
关注
28文章
1351浏览量
110065 -
代码
+关注
关注
30文章
4774浏览量
68503
原文标题:Verilog基础知识学习笔记(一)
文章出处:【微信号:zhuyandz,微信公众号:FPGA之家】欢迎添加关注!文章转载请注明出处。
发布评论请先 登录
相关推荐
评论