==============================================================================
==============================================================================
在编写testbench时,我们会用到一些VHDL语言,这些语言是我们不常用的,甚至以前没有见过的,但是在testbench中他们却是被经常用到,而且对我们的仿真编写非常有用。今天我们就来简单讲一下常用的几个VHDL句法。
一、文件I/O
上节讲了,在testbench常将数据写入文件,或者从文件读入数据等,这都需要用到VHDL语言中与文件打交道的语言,即是常说的file I/O. 这里强调两点:文件I/O语言是不能被综合的,文件I/O与FPGA的I/Opin是两回事。
根据存在文件中数据的不同,文件有多种类型,存入的数据可以是integer ,string,std_logic_vector 等等,但是定义时有区别,后面会说到。
对文件的操作有,定义文件,打开文件,从文件中读取数据,写入数据到文件等。
一、定义文件。
文件有两个大的类型,integer:文件中的数据是以二进制存取的,不能被人识别,只有integer型的数据能够存入这类文件。string:文件是以可以读取的ASCII码,可以被人识别,integer ,bit_vector(x downto x),string(x downto 1),std_logic_vector(x downto 0) ,bit等都可以被存入此类文件。
定义语法 file filein:text; type integerfile is file of integer file filein:integerfile;
二、打开文件。
86版的VHDL在定义文件时即将文件隐式的打开了,这里我们讲93版的文件打开语句。
在上一步定义了文件句柄后就可以在程序中打开指定文件,同时指定打开模式。
file_open(fstatus,file file_handle:file_type, filename:string,openmode)
fstatus指示当前文件状态,但是在使用前首先得定义一名variable fstatus:FILE_OPEN_STATUS;,一般有OPEN_OK,STATUS_ERROR,NAME_ERROR,MODE_ERROR四种状态。
file_handle即是上一步定义的文件类型的句柄filein.
filename是以双隐号括起的文件名,如"datain.txt";
openmode是指打开该文件的模式,文件打开有read_mode,write_mode,append_mode三种。
三、读写文件。
在上一步以什么模式打开,该步就可以对文件进行操作了,当上一步打开文件后,就可以用read(file_handle,value:type) write(file_handle,value:type)向文件读写数据了,但是这里特别注意,如果直接使用这两个语句,你只能向文件中写入指定类型的数据,如integer类型的只能写入integer型数据,text型只能写入string的数据,而不是像第二步说的那么多类型,要想写入其他类型必须遵守以下操作步骤!
(1)定义line型变量 variable buf:line,(2)将需要写入的数据写入line变量 write(buf,value)(这里的value就可以多种值),(3)从line变量把数据写入文件 writeline(file_handle,buf)。一定要按前后顺序来操作。
四、文件关闭。
在文件读写完毕后记得关闭文件file_close(file_handle),当然在文件操作中还有一个函数在反映是否读取到文件末尾ENDFILE(file_handle) 如果到达文件末尾将返回真(ture)否则返回假(false);
笔记:这里还要补充两种特殊的文件,input,output,也可以是“STD_INPUT","STD_OUTPUT"其实他们都是代表modelsim中的控制台,input和”STD_INPUT"就是从控制台输入数据,output "STD_OUTPUT"就是输出数据到控制台。后面两种格式要做为文件打开,前面一种可以直接作为文件句柄操作。如 file_open(fstatus,file_out,"STD_OUTPUT",write_mode); readline(output,buf);
同时有两个比较有用的写入语句 write(file_out,string'("hello")) write(file_out,bit_vector'(110"));
我们做了一个最完全的例子,将以上所有的操作包括进去,写了一个testbench,附录到下一节,同时将输出信息与被操作文件信息附录到图片,欢迎在下一节中获取源代码。
声明:以上操作均是基于VHDL1993版本!
=============================================================================
library ieee;
use std.textio.all;
use ieee.std_logic_textio.all;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity testin is
end entity testin;
architecture rtl of testin is
begin
process is
file file_out1,filein: text; --定义text类型的文件句柄;
variable fstatus1,fstatus2:FILE_OPEN_STATUS; --定义文件状态指示变量;
variable count:integer:=5; --定义integer型写入数据;
variable stringdata:string(5 downto 1):="whwnh";--定义string型写入数据;
variable vectordata:bit_vector(5 downto 0):="001000";--定义bit_vector型的写入数据;
variable value:std_logic_vector(3 downto 0):="1111";--定义std_logic_vector型的写入数据;
variable BUF,BUF1:LINE;
begin
file_open(fstatus1,file_out1,"datain.txt",write_mode); --打开文件“datain.txt"
write(file_out1,string'("the first parameter is=")); --通过write()函数直接向文件中写入对应类型数据。
readline(input,buf); --从控制台输入字符串输入文件;
write(buf,count);
writeline(file_out1,buf); --向文件中输入integer类型
wait for 20 ns;
write(buf,string'("the second parameter is="));
write(buf,value);
writeline(file_out1,buf);
wait for 20 ns; --向文件中输入std_logic_vector类型数据;
write(buf,string'("the third parameter is="));
write(buf,vectordata);
writeline(file_out1,buf);
wait for 20 ns; --向文件中输入bit_vector类型数据;
write(buf,string'("the forth parameter is="));
write(buf,stringdata); --向文件中输入string类型数据。
writeline(file_out1,buf);
write(file_out1,string'("end of file"));
file_close(file_out1);
wait for 100 ns; --关闭文件
file_open(fstatus1,file_out1,"datain.txt",read_mode); --以读取模式打开文件
readline(file_out1,buf); --读取文件数据并输出到控制台界面。
writeline(output,buf);
file_close(file_out1);
wait for 100 ns;
file_open(fstatus1,filein,"STD_INPUT",read_mode); --以控制台作为文件输入
file_open(fstatus2,file_out1,"STD_OUTPUT",write_mode); --以控制台作为文件输出
readline(filein,BUF);
writeline(file_out1,BUF);
wait;
end process;
end rtl;
控制台文件
输出.txt文件
==============================================================================
一、next,exit
这两个关键词有点类似于C语言中的continue和break.
PROCESS(A, B)
CONSTANT max_limit : INTEGER := 255;
BEGIN
FOR i IN 0 TO max_limit LOOP
IF (done(i) = TRUE) THEN
NEXT;
ELSE
done(i) := TRUE;
END IF;
q(i) <= a(i) AND b(i);
END LOOP;
END PROCESS;
如程序中用到了next,如果i还没有到达max_limit那么将会退出本次循环,i=i+1,然后继续循环。
PROCESS(a)
variable int_a : integer;
BEGIN
int_a := a;
FOR i IN 0 TO max_limit LOOP
IF (int_a <= 0) THEN -- less than or
EXIT; -- equal to
ELSE
int_a := int_a -1;
q(i) <= 3.1416 / REAL(int_a * i); -- signal
END IF; -- assign
END LOOP;
y <= q;
END PROCESS;
本例中使用了EXIT,当int_a<0时,那么程序将跳出loop循环,转而执行loop后的下一句话y<=q;
另外需要注意的是 EXIT支持嵌套,即是如果在loop中嵌套了loop,那么EXIT只会跳出最里层的loop.
另外EXIT还有一种语法 EXIT which_loop when(a<0); 在a<0满足时,跳出EXIT,不同的是现在的EXIT可以跳出指定loop(在loop有标签的情况下),如果没有指出,那么还是跳出最内层loop.
二、assert
assert是一个非常有用的语法,他可以判断一个boolean变量,如果该变量为假就输出一个用户指定的信息到终端(控制台),用户可以附带输出信息的严格等级,从低到高依次是:note,warning,error,failure,可以让用户区分信息的类型。同样assert语句也是不能被综合的。
assert可以同步语句(在process外),此时assert后面的任何变量变化都会引起assert语句判断一次。
assert还可以是顺序语句,此时assert存在于process中。
三、wait
使用wait语句,使设计者可以方便的在顺序语句中控制执行时间。可以用于process,procedure,function等子程序当中。
WAIT ON signal changes (signal)
WAIT UNTIL an expression is true (boolean_expression)
WAIT FOR a specific amount of time (time_expression)
PROCESS
BEGIN
WAIT UNTIL clock = ‘1’ AND clock’EVENT;
q <= d;
END PROCESS;
WAIT ON a, b; 只有a或者b 某一个信号变化才执行下面的语句。
WAIT UNTIL (( x * 10 ) < 100 ); 只有x<10才执行下面的句子,否则程序将会停在此处。
WAIT FOR 10 ns;
WAIT FOR ( a * ( b + c )); 程序在此处必须挂起这么多时间再执行下面的语句。
但是wait for语句会引起程序等待超时(有点像死锁),所以得注意使用。
可以使用语句 WAIT UNTIL (sendA = ‘0’) FOR 1 us;
ASSERT (sendA = ‘0’)
REPORT “sendA timed out at ‘0’”
SEVERITY ERROR; 这样可以消除等待超时。
process(clk) 相当于一个wait on clk在process的末尾,但是在有wait的process中不能有敏感信号表!同时注意wait on 必须在process的结尾。
文章评论(0条评论)
登录后参与讨论