目录
1、数据流建模(通过连续赋值语句进行逻辑描述的建模方式)
1.1连续赋值
连续赋值语句(assign)只能对连线型(wire等)变量进行赋值,分为显式连续赋值语句、隐式连续赋值语句。
1.1.1显式连续赋值语句
格式如下:
连线型变量类型 位宽 名称
assign #(延时)名称=变量赋值表达式
1.1.2隐式 连续赋值语句
格式如下:
连续型变量类型 赋值驱动强度 位宽 #(延时)名称=变量赋值表达式
(赋值驱动强度和延时是可选项)
//例如:
wire [3:0] a,b,c;
assign #(2,1,3) c = a|b; //显式
wire [3:0]#(2,1,3) c = a|b; //隐式
1.1.3连续赋值语句使用中的注意事项
1)赋值目标只能是wire型,且assign连续赋值语句不能出现在过程块中
2)多个连续赋值语句之间是并行关系,与位置顺序无关。
2、行为级建模(从电路外部行为的角度对其进行逻辑描述的建模方式)
2.1过程语句(initial、always)
2.1.1 initial过程语句
格式如下:
initial
begin
语句1;
语句2;
...
语句n;
end //它在仿真过程中只执行一次,之后就不再执行。
//例:用initial产生测试信号
module initial_tb;
reg s1;
initial
begin
s1=0;
#10 s1=1;
#20 s1=0;
#100 $stop;
end
endmodule
initial语句常出现于测试代码中,通常用于仿真模块中对激励向量的描述、或用于给reg型变量赋初值。
2.1.2 always过程语句
格式如下:
//例如:
always@(敏感事件列表)
语句块 //当列表中变量的值改变时,就会引发块内语句的执行
/*敏感信号分为边沿触发型、电平触发型两种。
电平触发:always@(a or b)
边沿触发:always@(posedge clk or negedge rst_n )*/
2.1.3 过程语句使用中的注意事项
1)在过程语句中,被赋值的信号必须定义为reg型
2)用其描述组合逻辑电路时,需把全部的输入的信号写入敏感列表 或always@(*)。
3)用其描述时序逻辑电路时,需把时间信号和部分输入信号写入敏感列表。
2.2语句块(当语句数超过一句时,需采用语句块)
2.2.1串行语句块(begin...end)
begin:块名 //当块内有变量时必须有块名,其他可有可无
块内声明语句 //其为可选项
语句1;
语句2;
...
语句n; //特点:依据块中的排列顺序逐条执行
end
2.2.2并行语句块(fork...join)
fork:块名 //其只能用于仿真测试程序,不能用于可综合电路程序。
块内声明语句;
语句1;
...
语句n; //块内语句同时执行
join
2.3过程赋值语句(在过程块中的赋值语句=、<=)
2.3.1阻塞赋值语句(=)
变量=表达式
1)在串行语句块中,各条阻塞赋值语句将按照顺序依次执行;在并行语句块中,则同时执行
2)执行顺序:先计算等号右边表达式的值,然后立即将计算的值赋给左边的变量。与仿真时间无关
2.3.2非阻塞赋值语句(<=)
变量<=表达式
1)在串行语句块中,各句并行执行。
2)执行顺序:先计算等号右边表达式的值,然后等待延迟时间的结束,再将计算的值赋给左边的变量。
2.4条件分支语句
2.4.1 if_else语句
//形式1: //形式4:
if(条件表达式) 语句块 if语句中允许多个if语句的嵌套
//形式2: if(条件表达式1)
if(条件表达式) if(条件表达式2)
语句块1; 语句块;
else else
语句块2; 语句块;
else
//形式3: if(条件表达式3)
if(条件表达式1) 语句块;
语句块1; else
else if(条件表达式2) 语句块;
语句块2; //形式多样,不一一列举了
...
else if(条件表达式n
语句块n;
else
语句块n+1;
注:
1)该语句本身隐含着一种优先级关系,条件表达式的优先级。这也是与case的不同之一。
2)if(a)= if(a==1),(对条件表达式进行判断时默认0、x、z按假处理,1按真处理)
2.4.2 case语句
case(控制表达式)
值1:语句块1;
值2:语句块2;
...
值n:语句块n;
default:语句块n+1;
endcase
//例:用case描述BCD数码管(看下图)
module BCD_decoder(out,in);
input [3:0] in;
output [6:0] out:
reg [6:0] out; //out在过程赋值语句always中赋值,得用reg类型赋值
always@(in)
begin
case(in)
4'b0000: out = 7'b1111110;
4'b0001: out = 7'b0110000;
4'b0010: out = 7'b1101101;
4'b0011: out = 7'b1111001;
4'b0100: out = 7'b0110011;
4'b0101: out = 7'b1011011;
4'b0110: out = 7'b1011111;
4'b0111: out = 7'b1110000;
4'b1000: out = 7'b1111111;
4'b1001: out = 7'b1111011;
default: out = 7'bxxxxxxx;
endcase
end
endmodule
注:
1)若值1到值n涵盖控制表达式的所有值可不用加default项;若未涵盖则需要加default,否则会产生锁存器
2)值1到值n必须各不相同,且他们的位宽必须与控制表达式位宽相同。(用于比较)
3)casez和casex时case的两种特殊形式:
在casez语句中,如果双方(控制表达式与值项)有一边的某一位的值是z,那么这一位的比较结果为真。
在casex语句中,如果双方(控制表达式与值项)有一边的某一位的值是x或z,那么这一位的比较结果为真。
2.5 循环语句(多用于测试仿真)
2.5.1 forever语句
表示永久循环,直到遇到系统任务$finish或disable语句。其一般用在initial过程语句中,不能独立写在程序中(与always不同)
//格式:
forever 语句或语句块
//例:用forever语句产生时钟信号
·timescale 1ns/1ns
module forever_tb;
reg clk;
initial
begin
clk = 0;
forever #50 clk = ~clk ; //产生周期为100ns的时钟
end
endmodule
2.5.2 repeat语句
//格式:
repeat(循环次数) 语句或语句块(循环体) //用其产生固定次数的循环
//例:用repeat产生有4个时钟周期的信号
initial
begin
clk = 0;
repeat(8) clk = ~clk;
end
2.5.3 while语句
//格式:
while(条件表达式) 语句或语句块 /* 为条件循环,若条件表达式为真,才重复循环执行循环体;
若为假,就不执行循环体 */
//例:用while产生时钟信号
initial
begin
clk = 0:
while(1) #50 clk = ~clk;
end
2.5.4 for语句
//格式:
for(循环变量赋初值;循环结束条件;循环变量增值)
语句块
/*先给循环变量赋初值,然后判断循环结束条件,若其为真
则执行语句块(循环体),然后进行循环变量增值操作,
循环至循环结束条件满足时,for语句结束*/
//例:用for语句实现一个8位移位寄存器
module shift_regist(q,d,rst_n,clk);
input d,clk,rst_n;
output [7:0] q;
reg [7:0] q;
integer i;
always@(posedge clk)
if(!rst_n)
q <= 8'b00000000;
else
begin
for(i=7;i>0;i=i-1)
q[i] <= q[i-1];
q[0] <= d;
end
endmodule
/*i=7时,7>0为真,则q[6]赋值到q[7],i=6时,6>0为真
则q[5]赋值到q[6]...以此类推q[0]赋值到q[1],最后输入
d赋值到q[0];当i=0时,0>0为假,结束for循环。可以看到实现
的是一个移位寄存器功能。*/
for部分循环语句用于可综合设计是需要一定设计经验的,容易出错,不建议在可综合设计中使用。
3、结构化建模
将电路描述成一个分级子模块系统,通过逐层调用这些子模块构成所需系统的描述方法。按照调用子模块的抽象级别分为:模块级建模、门级建模、开关级建模
3.1模块级建模
模块级建模就是模块的调用,第二章已讲。
3.2 门级建模
门级开关级建模相对简单这里就不过多赘述