第二讲 case语句及task任务块
实验任务:
(1)用case语句实现具有译码功能的模块(类似于3-8译码器);
(2)学会在testbench中使用task任务块语句,用它产生测试数据给待测模块;
(3)注意case语句的写法,思考:若case分支列举不全面,会出现什么不良后果?
实验内容及过程:
因本次实验简单,故直接贴出代码并予以简单的讲解,代码截图如下图所示:
注意事项:
在用Verilog语言设计数字电路的时候,出现多余无用的锁存器对电路危害大,应格外小心,消除锁存器的办法:①always中的敏感信号列表要写全(要包含case条件、赋值符号右边的变量);②所有条件分支要写全(包括default);③if—else语句要写全,不要只写if不写else,没有else的时候也要写一条空的else语句。
以下两个图展示了case条件分支写全与不全时综合后的结果:
图1 case条件分支不全时综合的RTL视图
图1为漏写了
3'd7:begin
o_data = 8'b0111_1111;
o_dv = 1'b1;
end
这条分支时综合后的结果,从图1可看出,在电路的输出端出现了8个latch,且它们都与MUX7的输出端相连。由此可见,是因为漏写了上面的那段语句。
在利用Quartus II综合设计的实例时,也会出现一些相关的警告,如图2所示:
图2 Quartus II综合时产生的警告
正确的RTL视图应该如图3所示:
图3 正确的RTL级视图(无latch)
在testbench中使用task任务块依次产生0~255之间的数,并分别将这些数值赋值给i_data和i_addr,代码截图如下图所示:
关于写task任务块,有很多语法约束,这里一一列举出来:
(1)task没有端口列表,但可以有输入变量列表,并且变量须在task内部予以声明(如上图中的size);
(2)输入输出端口可在task内部尽心声明,支持input、output以及inout三种端口信号;
(3)可以用integer或reg声明task要用到的变量,但不能用wire声明;
(4)task任务块也属于块语句,但与module—endmodule的架构类似,可仿照module—endmodule的架构task任务块,但是,task与always、initial属于同一层次,故task的内容要写在always块和initial块之外,但可在always块、initial块以及task任务块中调用task任务块(即:任务中可以再调用其他任务);
(5)调用任务时,需按照端口声明的顺序调用(跟模块实例化中的“按顺序”实例化的操作是类似的);
(6)任务不能实时输出,而是只能在整个任务结束时得到一个最终的结果,输出的值也是这个最终的结果的值,例如:
task seq;
output q;
begin
q = 0;
#10 q = 1;
end
endtask
上述代码仿真的结果是,调用此任务之后只会得到一个延迟10个时间单位的输出数据1,前10ns输出数据的状态是未知的,如图4所示:
图4 task不能实时输出的仿真图
(6)在仿真过程中如果出现多次调用同一个任务,且每次操作的值不同时,就可能出现由于地址空间相互覆盖而导致的结果错误。针对这一问题,通常使用自动任务解决此问题。
最后,贴出本例的仿真波形图,如图5所示:
图5 译码器和task任务块的功能仿真图
文章评论(0条评论)
登录后参与讨论