TEXTIO 在VHDL 仿真与磁盘文件之间架起了桥梁,使用文本文件扩展VHDL 的仿真功能。本文介绍TEXTIO 程序包,以一个加法器实例说明TEXTIO 的使用方法,最后使用ModelSim 对设计进行仿真,并分析仿真结果。
在对VHDL 源程序进行仿真时, 由于有的输入输出关系仅仅靠输入波形或编写testbench 中的信号输入是难以验证结果正确性的, 例如, 设计8 位加法器, 如果将所有的输入都验证一遍, 是非常麻烦的, 因为要全面判断输出是否正确需要一个个的验证。此外,若用VHDL 设计一个处理器, 需要读入指令,这时候采用文本文件非常必要。
TEXTIO 提供了VHDL 仿真时与磁盘文件的交互。在验证加法器时候, 可以将所有输入保存在一个文本文件中, 将其它软件计算出的结果保存在另外的文件中。在VHDL 仿真时,可以直接读取输入文件作为设计的输入参数, 并自动将结果与事先保存的文件相比较,给出一定的信息来确定结果的正确与否。在对VHDL 编写的处理器调试时, 可以将包括指令类型、源地址、目标地址在内的指令保存成文本文件, 利用TEXTIO 来读取这些指令。同时, 将结果及中间变量保存成文本文件,以事后判断是否正确及便于查找原因。
由于TEXTIO 的文本输入输出功能非常有限, 一些公司提供了扩展其功能的程序包,例如std_developerskit库中的std_iopak 程序包。在本文中,仅仅对TEXTIO 程序包做简单的介绍及其简单的使用。
1 TEXTIO介绍
TEXTIO 是VHDL 标准库STD 中的一个程序包(Package)。在该包中定义了三个类型:LINE 类型、TEXT类型以及SIDE 类型。另外,还有一个子类型(subtype)WIDTH。此外, 在该程序包中还定义了一些访问文件所必须的过程(Procedure)。
1.1 类型定义
(1)type LINE is access string
定义了LINE 为存取类型的变量,它表示该变量是指向字符串的指针,它是TEXTIO 中所有操作的基本单元。读文件时,先按行(LINE)读出一行数据,再对LINE 操作来读取各种数据类型的数据;写文件时, 先将各种的数据类型组合成LINE,再将LINE 写入文件。在用户使用时, 必须注意只有变量才可以是存取类型, 而信号则不能是存取类型。例如, 我们可以定义
variable DLine : LINE;
但不能定义成
signal DLine : LINE;
(2)type TEXT is file of string
定义了TEXT 为ASCII 文件类型。 定义成为TEXT 类型的文件是长度可变的ASCII 文件。例如在TEXTIO 中定义了两个标准的文本文件。
file input : TEXT open read_mode isSTD_INPUT;
file output : TEXT open write_mode isSTD_OUTPUT;
定义好以后,就可以通过文件类型变量input 和output 来访问其对应的文件STD _ INPUT 和STD_OUTPUT。
需要注意的是VHDL87 和VHDL93 在使用文件方面有较大的差异,在编译时注意选中对应的标准。
(3)type SIDE is (right,left)
定义了SIDE 类型。表示定义了一个名为SIDE 的数据类型,其中只能有两种状态,即right 和left,分别表示将数据从左边还是右边写入行变量。该类型主要是在TEXTIO 程序包包含的过程中使用。
(4)subtype WIDTH is natural
定义WIDTH 为自然数的子类型。所谓子类型表示其取值范围是父类型范围的子集。
1.2 过程定义
TEXTIO 提供了基本的用于访问文本文件的过程。类似于C++,VHDL 提供了重载功能, 即完成相近功能的不同过程可以有相同的过程名, 但其参数列表不同, 或参数类型不同或参数个数不同。
TEXTIO 提供的基本过程有:
procedure READLINE(文件变量;行变量);用于从指定文件读取一行数据到行变量中。
procedure WRITELINE(文件变量;行变量);用于向指定文件写入行变量所包含的数据。
procedure READ(行变量;数据类型);用于从行变量中读取相应数据类型的数据。
根据参数数据类型及参数个数的不同,有多种重载方式,TEXTIO 提供了bit、bit_vector 、BOOLEAN 、character、 integer、real、string、time数据类型的重载。同时, 提供了返回过程是否正确执行的BOOLEAN 数据类型的重载。例如, 读取整数的过程为
procedure READ(L:inout LINE; VALUE: out integer; GOOD: out BOOLEAN);其中,GOOD 用于返回过程是否正确执行, 若正确执行, 则返回TRUE 。
procedure WRITE(行变量; 数据变量; 写入方式; 位宽);
该过程将数据写入行变量。其中写入方式表示写在行变量的左边还是右边,且其值只能为left 或right,位宽表示写入数据时占的位宽。例如:
write(OutLine,OutData,left,2);
表示将变量OutData 写入LINE 变量OutLine 的左边占2 个字节。
2 TEXTIO应用实例
下面以一个简单的8 位加法器来说明TEXTIO 的使用。输入数据为两个8 位的有符号数, 输出为9 位的有符号数,以防止溢出。在编写加法器的描述文件时,首先要对两个数进行位的扩展,再进行加法运算。在编写测试文件时, 要注意读入数据与得到结果之间相差一个时钟周期。因此, 需要在读出的结果与计算的结果之间插入一个时钟周期的等待。
① 生成输入及预定结果文件的C++程序。
我们可以使用VC++、Matlab 等高级软件工具编写生成输入和预定结果文件的程序。由于设定输入为8 位有符号数, 因此,其范围为[-127,127]。C++程序如下:
#include iostream.h
#include stream.h
void main(void){
int i,j;
ofstreamfsIn(d:\\yuproj\\modelsim\\NineBitAdder2\\TestData.dat);
ofstreamfsOut(d:\\yuproj\\modelsim\\NineBitAdder2\\Result.dat);
for(i=-127;i<128;i++) {
for(j=-127;j<128;j++) {
fsIn< fsOut< }
}
fsIn.close();
fsOut.close();
}
在程序中,使用了C++类库iostream.h和fstream.h,主要使用了<< 的输出功能, 读者可以参考相应的C++书 籍。运行该程序可以在规定的目录下生成TestData.dat 和Result.dat 两个文本格式的文件。注意,一行输入多个数据时, 之间以空格隔开即可。
② 编写的加法器描述如下。
libraryieee;
useieee.std_logic_1164.all;
useieee.std_logic_signed.all;
entity Add2In is
port( D1 : in std_logic_vector(7 downto 0);
D2 : in std_logic_vector(7 downto 0);
Q : out std_logic_vector(8 downto 0);
Clk: instd_logic);
end Add2In;
architecture A_Add2In of Add2In is
begin
process(Clk)
begin
if Clk = ‘1’and Clk’event then
Q <= (D1(D1’left) & D1) + (D2(D2’eft) & D2);
endif;
endprocess;
end A_Add2In;
在进行加法前, 首先进行位的扩展, 再进行加法运算, 在时钟的上升沿完成加法运算。
③ 编写测试文件。
在测试程序中, 首先读出输入文件的一行内容,再从该行中提取出两个值输入加法器。从预定结果文件中提取出一个值, 将加法器计算结果与该值比较, 若两者不同则输出警告信息。也可以将输出写入一个文本文件, 再比较两个文本文件的异同以获知出错的地方。这里要注意的是要使用TEXTIO 程序包, 另外, 测试文件实体内的端口为空, 相当于一块独立的电路板。使用Component 在其中包含了上面定义的加法器, 该独立的电路板所完成的功能是对设计的加法器进行测试。在程序中使用了assert 断言语句,要注意该语句后的表达式或变量为真时不执行后续的输出,为假时执行后续的输出。在程序中,还使用了类型转换函数CONV _ STD _LOGIC_VECTOR (),将整数转换为8 位的标准类型。另外,在程序中定义了变量Dlatch ,该变量的作用是将计算结果与预定结果的比较延迟一个时钟周期, 周期地与预定结果比较。
3 仿真结果
在ModelSim 中可以将它们编译仿真,注意在编译时选择语法标准为VHDL93 标准。编译后, 可以输入如下的仿真Macro 来执行仿真。
vsim work.tb
该命令将执行仿真work 库中的tb,其中tb 为测试文件的实体名。
add wave -dec *
该命令将所有的信号以十进制添加到波形文件中。
run-all
该命令将使仿真一直执行下去。
输入以上各个命令,仿真结束后会在ModelSim 的提示符下出现如下信息:
# ** Fatal: (vsim-3551) TEXTIO : Read past end of file TestData.dat.
# Time: 2601020ns Iteration: 0 Process:/tb/line__34File: D:/YuProj/ModelSim/NineBitAdder2/NineBitAdder2.vhd
# FatalerroratD:/YuProj/ModelSim/NineBitAdder2/NineBitAdder2.vhd line 41
表示在读完TestData.dat 后,因读空出现错误。其中没有出现程序中所设定的warning ,表示加法器的仿真结果与高级软件得到的预定结果相符合。我们可以改进程序,在其中加入ENDFILE()函数来判断是否读取到文件的结尾。仿真得到的波形如图1 所示。
若人为地更改Result.dat文件中第9行的-246为100,重新仿真, 则出现如下信息:
# ** Warning: Two values are different
# Time: 420 ns Iteration: 0 Instance: /tb
# ** Fatal: (vsim-3551) TEXTIO : Read past end of file TestData.dat.
# Time: 2601020ns Iteration: 0 Process:/tb/line__34File: D:/YuProj/ModelSim/NineBitAdder2/NineBitAdder2.vhd
# FatalerroratD:/YuProj/ModelSim/NineBitAdder2/NineBitAdder2.vhd line 41
#
双击对应的警告信息,可以看到仿真结果与Result.dat 中预定结果不一致的地方。仿真图形如图2所示。
结语
TEXTIO 使得VHDL 的仿真功能有了大的飞跃, 在使用VHDL 描述处理器等模型及判断系统对不规则输入的响应时, 起到了非常大的作用。本文通过简单的实例,说明了TEXTIO 库及其简单的应用流程。在当前嵌入式系统广泛应用的背景下, 将更为需要TEXTIO 的应用。