该系列中的先前文章
普通计算机程序如何工作?有一定的外部环境(带有“鼠标”的显示器和键盘是这种环境的最典型代表)。该程序与他们互动。调试时,您可以从外部环境中产生真正的影响,也可以模拟它们。我们的测试人员经常编写各种脚本来模拟外部影响。之后,启动日志分析器,该分析器在星期三检查答案是否正确。
如果此计算机程序中的所有错误都怎么办?您可以设置断点并在命中时检查系统快照。系统的一部分是变量的值。可能是各种互斥锁和其他同步对象的状态。通常,是调试系统内部参数的快照。
在调试FPGA时,您可以做同样的事情。的确,如果环境是真实的,那么即使有可能,停止并研究系统的某个部分也是有问题的。作为有关Redd的故事的一部分,我一直在提倡这样的想法,即一切都应该简单快速。我们不设计复杂的系统。我们正在做某种模块,就像上一篇文章中完成的那样。它很复杂,但是非常简单。通常,我们将进行行为建模。
这里出现了有关外部环境的问题。如何模拟呢?模型对我们有帮助。 Verilog(以及VHDL和其他类似的语言)很有可能描述任何事物的行为。我们正在开发一种可与ULPI微型电路配合使用的系统...因此,为了测试其工作性能,另一端的某些行为必须与ULPI完全相同。即,ULPI模型。但这还不够。我们的块对来自ALAVON_MM总线的命令作出反应。正是此总线使该块生效。因此,我们还需要添加总线模型AVALON_MM,并且该模型必须处于活动状态。她将提交测试影响力。
最终,我们必须建立这样一个系统。然后,我们将能够在其所有总线上甚至在其任何模块内部记录信号的时序图。如果发生错误,我们可以设置断点并检查系统快照以找到敌人。尽管就我个人而言,通常我不设置这些断点,但是通常,对时序图进行分析就足够了。事实是,不仅可以查看接口信号,还可以查看任何内部信号。拉出图表上的一两个内部信号,通常可以猜出逻辑上有什么问题。
今天的文章的目的不是要讨论一般的建模(这是一个漫长的故事),而是要展示如何最快速地进行建模。我们将考虑的不是一个作战任务,而是一个简单的例子。让我们做一个非常简单的测试系统,以便在下一篇文章中我们已经了解了它的更复杂版本的来源,因为在阅读时更容易坐下来而不想:“他为什么这样做?”,但是要知道所有基本原理,由此而来的并发症已经产生...顺便说一下,最近发现我的一个熟人,尽管他拥有建模技巧,却不知道Quartus环境具有内置的机制,可以让您轻松自然地完成此任务。他在这方面花费了很多精力。因此,也许有人现在也会为自己学习一些有关Quartus内在可能性的新知识。所以,让我们开始吧。
Verilog
人们分为两类。那些喜欢用手从头开始创建一切的人,以及那些喜欢用鼠标来完成它的人。用双手创造一切更正确。您可以控制每个动作,并尽一切所能。但是记忆是不可靠的。如果她一直都在做同一件事,那么她会牢记细节,如果必须一直在两种语言之间切换,那么一两个月后,她必须记住在那里需要做什么。因此,仅由于这个原因,通过选项“使用鼠标修补匠”才能存在。同样,如果要调试的模块具有十几个接口信号,那么我总是很无聊地进行重新声明和转发它们的例行工作。因此,现在我们将考虑如何使用“鼠标”制作模型。然后-每个人都将自己决定这对他是否足够,还是应该改用手工工作。
因此,我们要模拟模块。 “模拟”超出了我们的周期范围,您可以在该主题上写一个单独的大周期。也就是说,在本节的框架内,我们假定您熟悉开发模型的方法。但是,那么一切都需要包含在项目中……还是不?奇怪的是,您甚至无需创建自己的项目即可对模块进行建模。我们可以将其作为寄生虫附加到任何项目,而无需在其中包含任何新内容,而只能通过创建一个不会以任何方式参与主装配的测试套件来进行。
为了感兴趣,让我们在我们的ULPI项目上附加一个SystemVerilog上的有趣模块,该模块由我专门为说明而编写,与开发的分析仪无关。就在前一段时间,我在计算校验和时费解了很多,于是浮现在脑海。
module sum(
input clk,
input [7:0] data,
input we,
input sof,
output [15:0] sum
);
logic [15:0] temp;
always @ (posedge clk)
begin
if (we)
begin
if (sof)
temp <= data;
else
temp <= temp + data;
end
end
// -
//assign sum = (~temp)+1;
// :
assign sum = temp;
endmodule
可以看到,数据是通过总线传给它的,这很像AVALON_MM,很容易以并行代码输出。
让我们将结果文件放在我们项目的目录中,但是我们不会将其包含在Quartus的项目中。相反,我们将专门为其创建一个测试套件。为此,请选择菜单项分配->设置:,
然后在显示的树中查找项目EDA工具设置->模拟:
顺便说一下,以绿色框突出显示的模拟类型。也许有人记得在最初的文章中我曾说过,纯粹出于习惯,在创建项目时,我会选择ModelSim Altera吗?正是舞台上的枪,迟早要开火。但是,如果在创建项目时未选择建模类型,则可以在此处选择或更改它。
我们将继续创建测试套件。切换单选按钮来编译测试台(顺便说一下,请问这个词精美翻译成俄文,我不能让自己写的“试验台”,因为我没有看到任何板凳?),然后按该试验台按钮:
在打开的对话框中,按新:
如果做手动测试用例,您可以一次性填写这些字段。但是由于我们使用鼠标完成所有操作,因此现在仅填写部分字段,稍后再填写其余字段。在测试台名称字段中我输入了Parazit一词(还有什么可以称呼寄生在项目上的测试?)。下方的Parazit一词是自动填写的。现在我们不会更改它,但是将来我们仍然必须这样做。另外,使用“ ...”按钮,我选择了要调试的加法器代码的sum.sv文件,然后使用“添加”按钮将其推入测试文件列表。现在就这样。关闭对话框...
接下来,我们将继续在ModelSim环境中进行测试。为此,选择菜单项“工具”->“运行仿真工具”->“ RTL仿真”:
将打开“ ModelSim”窗口。也许会在Verilog代码中发现错误,然后您需要关闭ModelSim,更正错误并重新打开。但是迟早,错误列表将纯粹是组织性的。在我看来是这样的:
找不到顶级模块。这个是正常的。我们尚未创建它。因此,我们在库列表中工作并打开它。这是我们的加法器。
将鼠标悬停在其上方,按鼠标右键,然后选择“创建波形”菜单项。这段文字太无聊了,如果我正在拍摄视频,整个过程将花费数十秒,因此请不要惊慌,但请多加注意。因此,创建波形...
模块的界面信号自动移至图表:
有必要为其中之一分配一个值。不管哪个,任命都很重要。 Quartus非常旧的建模环境擅长生成时钟信号。 las,很久以前,由于他们开始附加ModelSim,因此将其从交付中撤回了,这里的一切都不是那么漂亮。我没有看到在此处生成生成器的意义,所以我什至不会展示它。好吧,让我们将行设置为零。我们针对信号,按下右键,选择菜单项“编辑”->“波形编辑器”->“创建/修改波形”。
在出现的对话框中,选择“常量”。同时,我们将时间更改为100微秒:
接下来,我们将值指定为0:
我们已经创建了所需的最小数据集,其余的将更容易用笔完成。我们导出文件。为此,请选择菜单项“文件”->“导出”->“波形”:
选择文件类型Verilog Testbench(顺便说一句,遗憾的是它不是SystemVerilog,但是将来可以用笔进行校正)。我们还设置了文件名。我将其命名为parazit_tb,其原因是“为什么不呢?”
就是这样,可以关闭ModelSim,而无需保存临时房屋。
接下来如何处理模型
这是一个歪曲的但仍是现成的Verilog文件,该文件是为我们创建的系统:
`timescale 1ns / 1ns
module parazit_tb ;
reg sof ;
reg we ;
wire [15:0] sum ;
reg [7:0] data ;
reg clk ;
sum
DUT (
.sof (sof ) ,
.we (we ) ,
.sum (sum ) ,
.data (data ) ,
.clk (clk ) );
// "Constant Pattern"
// Start Time = 0 ns, End Time = 100 us, Period = 0 ns
initial
begin
end
initial
#0 $stop;
endmodule
自动化使我们不必编写积木。而且,如果有更多的接口信号,自动化将顺从地注册并连接所有电路。就个人而言,当我手动创建测试套件时,令人沮丧的是描述信号及其转发的过程。现在,在此文件中,我们现在将创建一个环境模型,该模型将影响调试的sum模块。
如您所见,设置振荡器产生的常数没有任何意义。但是尽管如此,所有电路都已创建,要测试的模块已连接,即使初始部分也已创建。让我们优化代码。首先,我们将通过删除以下行来删除断点:
initial
#0 $stop;
接下来,我们将添加一个时钟发生器模型(我怎么会怀念旧Quartus制造的出色发生器!您可以将频率设置为兆赫,而不用考虑将其重新计算为一个周期,甚至更不用说半个周期了)。
always
begin
clk = 0;
#5;
clk = 1;
#5;
end
现在我们需要发送一些数据字节。要做到这一点最简单的方法是正确的,在最初的部分,但如果我写的每个总线访问阶段出现,本节中的代码将变得混乱。因此,我将执行以下任务(由她充当轮胎模型):
task SendByte (input reg[7:0] D);
begin
data = D;
we = 1;
@(posedge clk);
#1
we = 0;
end
endtask
好吧,我将在初始块中编写使用总线的常量的用途和循环的调用。让我提醒您,记录类型#123的意思是“等待123个时间单位”。我们可以在十亿分之一秒内得到它。我还提醒您,由于分配是顺序的,因此我们使用“相等”运算,而不是“箭头”。因此,我们有以下主要测试代码:
在这里观看
initial
begin
sof = 0;
we = 0;
data = 0;
#13;
//
sof = 1;
SendByte (1);
//
sof = 0;
SendByte (5);
SendByte (1);
//
#20;
SendByte (1);
end
总的来说,我们完整的模块代码如下所示:
查看完整的模块代码。
`timescale 1ns / 1ns
module parazit_tb ;
reg sof ;
reg we ;
wire [15:0] sum ;
reg [7:0] data ;
reg clk ;
sum
DUT (
.sof (sof ) ,
.we (we ) ,
.sum (sum ) ,
.data (data ) ,
.clk (clk ) );
always
begin
clk = 0;
#5;
clk = 1;
#5;
end
task SendByte (input reg[7:0] D);
begin
data = D;
we = 1;
@(posedge clk);
#1
we = 0;
end
endtask
// "Constant Pattern"
// Start Time = 0 ns, End Time = 100 us, Period = 0 ns
initial
begin
sof = 0;
we = 0;
data = 0;
#13;
//
sof = 1;
SendByte (1);
//
sof = 0;
SendByte (5);
SendByte (1);
//
#20;
SendByte (1);
end
endmodule
完成测试用例准备
现在是时候将该文本添加到测试套件中了。为此,请转到
我们已经知道的对话框。但是现在我们不创建集合,而是从列表中选择它。将来,列表会随着添加的集而增加。选择后,按“编辑”按钮。我对设置进行了三处修改:
- 将parazit_tb.v文件添加到列表中。
- 由于顶级模块在parazit_tb.v文件中具有名称parazit_tb(您可以通过查看上一节的源代码来确保此名称),因此我在测试基准行的顶级模块中输入了该名称。
- 我说过将模拟运行10微秒,然后暂停。如果有的话,我将通过按手动控制按钮来完成。
总
我们关闭一切。再次运行ModelSim。我们看到一切正常。数据输入并计入数量。如果时钟上没有数据(我们为零),则数量不会增加。
如何使用建模环境本身是几篇文章的主题。更有可能是视频格式。但总的来说,我们熟悉从Quartus环境中以Verilog语言快速准备和运行测试的方法。
现在,我们知道如何快速运行仿真,我们可以为USB分析仪测头绘制一个环境模型并进行测试。同时,我们没有记住一个ModelSim拼写,因为Quartus允许您使用“鼠标”来配置所有内容。他自己生成所有必需的脚本,然后自己调用ModelSim环境。我们还以自动模式创建了模型的基础,尽管随后我们不得不手动对其进行修改。
las,嗯。外部环境的要素之一是ULPI模块。要自行开发其模型,首先,必须仔细了解该微电路的操作逻辑。在上一篇文章中,我说这非常棘手。其次,您需要花费大量时间来开发模型代码。并消除其中的错误...显然,找到现成的东西更容易。但是现成的模型仅在SystemC语言中找到。因此,在下一篇文章中,我们将学习使用这种语言为系统建模。