Verilog部分系统函数用法

ISE与ModelSim联合仿真时,在仿真文件中如何读取txt文档数据和写入txt文档。

一、读取txt文档数据

在Verilog HDL程序中有两个系统任务$readmemb和$readmemh用来从文件中读取数据到存贮器中。这两个系统任务可以在仿真的任何时刻被执行使用,其使用格式共有以下六种:
1) $readmemb("<数据文件名>",<存贮器名>);
2) $readmemb("<数据文件名>",<存贮器名>,<起始地址>);
3) $readmemb("<数据文件名>",<存贮器名>,<起始地址>,<结束地址>);
4) $readmemh("<数据文件名>",<存贮器名>);
5) $readmemh("<数据文件名>",<存贮器名>,<起始地址>);
6) $readmemh("<数据文件名>",<存贮器名>,<起始地址>,<结束地址>);

在这两个系统任务中,被读取的数据文件的内容只能包含:空白位置(空格,换行,制表格(tab)和form-feeds),注释行(//形式的和/*...*/形式的都允许),二进制或十六进制的数字。数字中不能包含位宽说明和格式说明,对于$readmemb系统任务,每个数字必须是二进制数字,对于$readmemh系统任务,每个数字必须是十六进制数字。数字中不定值x或X,高阻值z或Z,和下划线(_)的使用方法及代表的意义与一般Verilog HDL程序中的用法及意义是一样的。另外数字必须用空白位置或注释行来分隔开。

在下面的讨论中,地址一词指对存贮器(memory)建模的数组的寻址指针。当数据文件被读取时,每一个被读取的数字都被存放到地址连续的存贮器单元中去。存贮器单元的存放地址范围由系统任务声明语句中的起始地址和结束地址来说明,每个数据的存放地址在数据文件中进行说明。当地址出现在数据文件中,其格式为字符“@”后跟上十六进制数。如:
                                                                           @hh...h
对于这个十六进制的地址数中,允许大写和小写的数字。在字符“@”和数字之间不允许存在空白位置。可以在数据文件里出现多个地址。当系统任务遇到一个地址说明时,系统任务将该地址后的数据存放到存贮器中相应的地址单元中去。

举例说明:

先定义一个有256个地址的字节存贮器 mem:
                                                                  reg[7:0] mem[1:256];
下面给出的系统任务以各自不同的方式装载数据到存贮器mem中。
initial $readmemh("mem.data",mem);
initial $readmemh("mem.data",mem,16);
initial $readmemh("mem.data",mem,128,1);
第一条语句在仿真时刻为0时,将装载数据到以地址是1的存贮器单元为起始存放单元的存贮器中去。第二条语句将装载数据到以单元地址是16的存贮器单元为起始存放单元的存贮器中去,一直到地址是256的单元为止。第三条语句将从地址是128的单元开始装载数据,一直到地址为1的单元。在第三种情况中,当装载完毕,系统要检查在数据文件里是否有128个数据,如果没有,系统将提示错误信息。

应用说明:

此部分为自己的实例。

 reg  [7:0]  my_mem [0:65535];//定义一个有65536个地址的字节存贮器
 $readmemh("128by512_init.txt", my_mem);//将txt文档中的数据存储到my_mem中

txt文档中的格式说明,因为使用readmemh读取数据,所以文档中的数字为十六进制,一个数据一行。

二、写入txt数据

integer fouti;
fouti = $fopen("result.txt");//写入文档
$fwrite(fouti, "%d", data_out, "\n");//写入数据

(1)fwrite是需要触发条件的,在一次触发条件之后也不会自动发生换行,所以要求手动添加换行。

(2)如果写入数据的格式为%d,则认为是无符号数。

三、$display和$write任务

格式:

$display(p1,p2,....pn);
$write(p1,p2,....pn);

这两个函数和系统任务的作用是用来输出信息,即将参数p2到pn按参数p1给定的格式输出。参数p1通常称为“格式控制”,参数p2至pn通常称为“输出表列”。这两个任务的作用基本相同。$display自动地在输出后进行换行,$write则不是这样。如果想在一行里输出多个信息,可以使用$write。在$display和$write中,其输出格式控制是用双引号括起来的字符串,它包括两种信息:

(1)格式说明,由"%"和格式字符组成。它的作用是将输出的数据转换成指定的格式输出。格式说明总是由“%”字符开始的。对于不同类型的数据用不同的格式输出。表一中给出了常用的几种输出格式。

(2)普通字符,即需要原样输出的字符。其中一些特殊的字符可以通过表二中的转换序列来输出。下面表中的字符形式用于格式字符串参数中,用来显示特殊的字符。

在$display和$write的参数列表中,其“输出表列”是需要输出的一些数据,可以是表达式。下面举几个例子说明一下。

[例1]:

module disp;
    initial
        begin
            $display("\\\t%%\n\"\123");
        end
endmodule

输出结果为

\%
"S

从上面的这个例子中可以看到一些特殊字符的输出形式(八进制数123就是字符S)。

[例2]:

module disp;
    reg[31:0] rval;
    pulldown(pd);
    initial
        begin
            rval=101;
            $display("rval=%h hex %d decimal", rval, rval);
            $display("rval=%o otal %b binary", rval, rval);
            $display("rval has %c ascii character value",rval);
            $display("pd strength value is %v",pd);
            $display("current scope is %m");
            $display("%s is ascii value for 101",101);
            $display("simulation time is %t",$time);
        end
endmodule

其输出结果为:

rval=00000065 hex 101 decimal
rval=00000000145 otal 00000000000000000000000001100101 binary
rval has e ascii character value
pd strength value is StX
current scope is disp
e is ascii value for 101
simulation time is 0

四、系统任务$finish

格式:

$finish;
$finish(n);

系统任务$finish的作用是退出仿真器,返回主操作系统,也就是结束仿真过程。任务$finish可以带参数,根据参数的值输出不同的特征信息。如果不带参数,默认$finish的参数值为1。下面给出了对于不同的参数值,系统输出的特征信息:

0 不输出任何信息

1 输出当前仿真时刻和位置

2 输出当前仿真时刻,位置和在仿真过程中所用memory及CPU时间的统计

五、系统任务$stop

格式:

$stop;
$stop(n);

$stop任务的作用是把EDA工具(例如仿真器)置成暂停模式,在仿真环境下给出一个交互式的命令提示符,将控制权交给用户。这个任务可以带有参数表达式。根据参数值(0,1或2)的不同,输出不同的信息。参数值越大,输出的信息越多。

六、应用实例

module main_test;

	// Inputs
	reg all_clk_50M;
	reg all_RSTn;

	reg [7:0] my_mem [0:65535];
	reg [13:0] pix_cnt;   
	reg [16:0] save_cnt;
	reg [63:0] data_in;
	integer fouti;
	// Outputs
	wire [7:0] data_out;
	wire wr_done_sig;
	wire save_done_sig;

	// Bidirs
	wire [63:0] data_inout;

	// Instantiate the Unit Under Test (UUT)
	main uut (
		.all_clk_50M(all_clk_50M), 
		.all_RSTn(all_RSTn), 
		.data_inout(data_inout), 
		.data_out(data_out), 
		.wr_done_sig(wr_done_sig), 
		.save_done_sig(save_done_sig), 
	);

	initial begin
		// Initialize Inputs
		all_clk_50M = 0;
		all_RSTn = 1;
        fouti = $fopen("medfilter2_re.txt");
		$readmemh("743_128by512_init.txt", my_mem);
		// Wait 100 ns for global reset to finish
		#100;
        all_RSTn = 0;
		// Add stimulus here
		#100;
		pix_cnt = 1;
		save_cnt = 1;
		data_in = {my_mem[0],my_mem[1],my_mem[2],my_mem[3],my_mem[4],my_mem[5],my_mem[6],my_mem[7]};
		// Add stimulus here

	end
	/*******************************************************************************/	
	assign data_inout = 1 ? data_in : 64'hzzz ;

	always #10 all_clk_50M = ~all_clk_50M;
	//写入数据的过程
	/*******************************************************************************/
	always@(posedge all_clk_50M)
		begin
			if(wr_done_sig)
				begin
				 pix_cnt <= pix_cnt + 1;
				 data_in = {my_mem[pix_cnt*8],my_mem[pix_cnt*8+1],my_mem[pix_cnt*8+2],my_mem[pix_cnt*8+3],my_mem[pix_cnt*8+4],my_mem[pix_cnt*8+5],my_mem[pix_cnt*8+6],my_mem[pix_cnt*8+7]};
				end
		end
	always@(posedge all_clk_50M)
		begin
			if(wr_done_sig)
				begin
				    $display("pix_cnt = %d",pix_cnt);
				end
		end
	//输出结果的过程
	/*******************************************************************************/
	always@(posedge all_clk_50M)
		begin
			if(save_done_sig)
				save_cnt <= save_cnt + 1;
		end
	/*******************************************************************************/
	always@(posedge all_clk_50M)
		begin
			if(save_done_sig)
				begin
				    $fwrite(fouti, "%d", data_out, "\n");
				    $display("save_cnt = %d",save_cnt);
				end
		end
	/*******************************************************************************/
	always@(posedge all_clk_50M)
		begin
			if(save_cnt == 17'd65537)
				begin 
				    $display("Image Completed!\n");
				    $display("The all time is %d \n",$time);
				    $stop;
				end
		end
endmodule

参考资料:《Verilog数字系统设计教程》夏宇闻

转载请注明出处,谢谢。

猜你喜欢

转载自blog.csdn.net/weixin_38621214/article/details/83791445