22.Verilog知识点(1)

1.如果 if 语句使用不当, 没有 else,可能会综合出来意想不到的锁存器。在 always 块里面,如果在给定的条件下变量没有被赋值,这个变量将会保持原来的值,也就是说会生成一个锁存器。

 

需要注意的是,这里说的是可能,
因此, 不代表没有 else 就一定会出现锁存器,同时,不代表有 else 就一定不会出现锁存器。这个是根据具体设计来看的。

避免锁存器
同 if else, case 应当加上 default,以避免锁存器出现。注意,如果 case 的情况是完备的,可以不加。(完备意为所有情况都设计了)

2.缩位运算

reg [3:0] B;
reg C;
C = &B;
相当于:
C =( (B[0]&B[1]) & B[2] ) & B[3];

3.数据类型

reg, integer, real, time 都是寄存器数据类型,定义在 Verilog 中用来保存数值的变量,和实
际的硬件电路中的寄存器有区别。
reg 型和 wire 型的区别在于: reg 型保持最后一次的赋值,而 wire 型则需要持续的驱动。

4.for循环

for 循环会被综合器展开为所有变量情况的执行语句,每个变量独立占用寄存器资源。简单的说就是: for 语句循环几次,就是将相同的电路复制几次,因此循环次数越多,占用面积越大,综合就越慢。

注意, i 的变化不跟时钟走:
在 Verilog 中使用 for 循环的功能就是,把同一块电路复制多份,完全起不到计数的作用,所以这个 i 的意思是复制多少份你这段代码实现的电路,和时钟没有任何关系。主要是为了提高编码效率。

5.generate

1)一个是用来构造循环结构,用来多次实例化某个模块。

2)一个是构造条件 generate 结构,用来在多个块之间最多选择一个代码块,条件 generate 结
构包含 if--generate 结构和 case--generate 形式。

3)还有一个是用来断言

generate 在建模(elaboration)阶段实施,出现预处理之后,正式模拟仿真之前。因此。 generate 结构中的所有表达式都必须是常量表达式,并在建模(elaboration)时确定。例如, generate 结构可能受参数值的影响,但不受动态变量的影响。


generate 循环的语法与 for 循环语句的语法很相似。但是在使用时必须先在 genvar 声明中声明循环中使用的索引变量名,然后才能使用它。 genvar 声明的索引变量被用作整数用来判断 generate 循环。 genvar 声明可以是 generate 结构的内部或外部区域并且相同的循环索引变量可以在多个 generate 循环中只要这些环不嵌套genvar 只有在建模的时候才会出现,在仿真时就已经消失了

在“展开”生成循环的每个实例中,将创建一个隐式 localparam,其名称和类型与循环索引变
量相同。它的值是“展开”循环的特定实例的“索引”。可以从 RTL 引用此 localparam 以控制生
成的代码,甚至可以由分层引用来引用。

6.function函数
verilog 中的 function 只能用于组合逻辑;
定义函数的语法
function <返回值的类型或范围> <函数名>
<端口说明语句>
<变量类型说明>
begin
<语句>

end
endfunction
说明:
1 function [7:0] getbyte ;
2 input [15:0] address ;
3 begin
4 <说明语句> //从地址字节提取低字节的程序
5 getbyte = result_expression ; //把结果赋给函数的返回字节
6 end
7 endfunction

函数使用的规则
1 函数定义不能包含有任何的时间控制语句,即任何用#、 @、 wait 来标识的语句。
2 函数不能调用task
3 定义函数时至少要有一个输入参数。
4 在函数的定义中必须有一条赋值语句给函数中与函数名同名、位宽相同的内部寄存器赋
值。

5<返回值的类型或范围>这一项为可选项,如果缺失,则返回值为一位寄存器类型数据

module func_ex_01 (
input clk , //E1 25M
output led //G2 高电平 灯亮
);
///*counter_01*
reg [25:0] counter_01 = 26'd0 ;
always @ (posedge clk)
begin
counter_01 <= counter_01 + 1'b1 ;
end
/*& function*/
function [3:0] yu ;
input [3:0] a ;
input [3:0] b ;
begin
yu = a & b ;
end
endfunction
reg [3:0] reg_a = 4'b0101 ;
reg [3:0] reg_b = 4'b1010 ;
wire [3:0] result ;
assign result = yu(reg_a , reg_b) ;
//*verify and display*
assign led = (result == 4'd0) ? counter_01[25] : 1'b0 ;
endmodule

7.任务task
        任务就是一段封装在“task-endtask”之间的程序。任务是通过调用来执行的,而且只有在调用时才执行,如果定义了任务,但是在整个过程中都没有调用它,那么这个任务是不会执行的。调用某个任务时可能需要它处理某些数据并返回操作结果,所以任务应当有接收数据的输入端和返回数据的输出端。另外,任务可以彼此调用,而且任务内还可以调用函数

1)任务定义
task task_id;
[declaration]
procedural_statement
endtask
其中,关键词 task 和 endtask 将它们之间的内容标志成一个任务定义, task 标志着一个
任务定义结构的开始; task_id 是任务名;可选项 declaration 是端口声明语句和变量声明语
句,任务接收输入值和返回输出值就是通过此处声明的端口进行的; procedural_statement
是一段用来完成这个任务操作的过程语句,如果过程语句多于一条,应将其放在语句块内;
endtask 为任务定义结构体结束标志。下面给出一个任务定义的实例。

task task_demo; //任务定义结构开头,命名为 task_demo
input [7:0] x,y; //输入端口说明
output [7:0] tmp; //输出端口说明
if(x>y) //给出任务定义的描述语句
tmp = x;
else
tmp = y;
endtask

2)注意:

(1)在第一行“task”语句中不能列出端口名称;
(2)任务的输入、输出端口和双向端口数量不受限制,甚至可以没有输入、输出以及
双向端口。
(3)在任务定义的描述语句中,可以使用出现不可综合操作符合语句(使用最为频繁
的就是延迟控制语句) ,但这样会造成该任务不可综合。

(4)在任务中可以调用其他的任务或函数,也可以调用自身。
(5)在任务定义结构内不能出现 initial 和 always 过程块。
(6)在任务定义中可以出现“disable 中止语句” ,将中断正在执行的任务,但其是不
可综合的。当任务被中断后,程序流程将返回到调用任务的地方继续向下执行。

3)任务调用
(1)任务调用语句只能出现在过程块内;
(2)任务调用语句和一条普通的行为描述语句的处理方法一致;
(3)当被调用输入、输出或双向端口时,任务调用语句必须包含端口名列表,且信号端口顺序和类型必须和任务定义结构中的顺序和类型一致。需要说明的是,任务的输出端口必须和寄存器类型的数据变量对应。
(4)可综合任务只能实现组合逻辑,也就是说调用可综合任务的时间为“0” 。而在面向仿真的任务中可以带有时序控制,如时延,因此面向仿真的任务的调用时间不为“0” 。
 

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值