0.关于verilog的可综合与不可综合
一般综合工具支持的Verilog HDL结构:
一般综合工具不支持的Verilog HDL结构
一般综合工具忽略的Verilog HDL结构
可综合设计的要点
- 不使用初始化语句。
- 不使用带有延时的描述。
- 不使用循环次数不确定的循环语句,如forever、while等。
- 尽量采用同步方式设计电路
- 除非是关键路径设计,一般不采用调用门级元件来描述设计的方法,建议采用行为语句来完成设计。
- 用always过程块描述组合逻辑,应在敏感信号列表中列出所有的输入信号。
- 所有的内部寄存器都应该能够被复位,应尽量使用器件的全局复位端作为系统总的复位。
- 用户自定义原语(UDP元件)是不可综合的,它只能用来建立门级元件的仿真模型。
1.verilog有两类数据类型:
wire用法总结:
1. wire可以在Verilog中表示任意宽度的单线/总线
2. wire可以用于模块的输入和输出端口以及一些其他元素并在实际模块声明中
3. wire不能存储值(无状态),并且不能在always @块内赋值(=或<=)左侧使用
4. wire是assign语句左侧唯一的合法类型
5. wire只能用于组合逻辑
reg用法总结:
6. 类似于电线,但可以存储信息(有内存,有状态)允许连接到模块的输入端口,但不能连接到实例化的输出
7. 在模块声明中,reg可以用作输出,但不能用作输入
8. 在always@(......)语句块内,= 或者 <= 赋值语句的左边必须是是reg变量
在initial语句块内,= 赋值语句的左边必须是是reg变量
9. Reg不能用于assign赋值语句的左侧
10. 当与@(posedge clock)块一起使用时,reg可用于创建寄存器
11. reg可用于组合逻辑和时序逻辑
关于TOP和Testbench的2种类型限制:
2.Verilog 中关键字全部为小写
3.存储字符串 “www.runoob.com”
reg [0: 14*8-1] str ;
initial begin
str = "www.runoob.com";
end
4.数组
定义操作:
integer flag [7:0] ; //8个整数组成的数组
reg [3:0] counter [3:0] ; //由4个4bit计数器组成的数组
wire [7:0] addr_bus [3:0] ; //由4个8bit wire型变量组成的数组
wire data_bit[7:0][5:0] ; //声明1bit wire型变量的二维数组
reg [31:0] data_4d[11:0][3:0][3:0][255:0] ; //声明4维的32bit数据变量数组
赋值操作:
flag [1] = 32'd0 ; //将flag数组中第二个元素赋值为32bit的0值
counter[3] = 4'hF ; //将数组counter中第4个元素的值赋值为4bit 十六进制数F,等效于counter[3][3:0] = 4'hF,即可省略宽度;
assign addr_bus[0] = 8'b0 ; //将数组addr_bus中第一个元素的值赋值为0
assign data_bit[0][1] = 1'b1; //将数组data_bit的第1行第2列的元素赋值为1,这里不能省略第二个访问标号,即 assign data_bit[0] = 1'b1; 是非法的。
data_4d[0][0][0][0][15:0] = 15'd3 ; //将数组data_4d中标号为[0][0][0][0]的寄存器单元的15~0bit赋值为3
虽然数组与向量的访问方式在一定程度上类似,但不要将向量和数组混淆。向量是一个单独的元件,位宽为 n;数组由多个元件组成,其中每个元件的位宽为 n 或 1。它们在结构的定义上就有所区别。
5.`default_nettype
//Z1无定义就使用,由于编译指令的存在,系统会报Error,从而检查出书写错误
`default_nettype none
module test_and(
input A,
input B,
output Z);
assign Z1 = A & B ;
endmodule
该实例定义后,将不再自动产生 wire 型变量。
6.`unconnected_drive
`unconnected_drive pull1
. . .
/ *在这两个程序指令间的所有未连接的输入端口为正偏电路状态(连接到高电平) * /
`nounconnected_drive
`unconnected_drive pull0
. . .
/ *在这两个程序指令间的所有未连接的输入端口为反偏电路状态(连接到低电平) * /
`nounconnected_drive
6. {CF,res}=a+ b+1;
verilog为什么这样写无法取得正确的进位CF:
{CF,res}=a+ b+1;
而这样写可以:
B=b+1;
{CF,res}=a+ B;
在Verilog中,{CF, res} = a + b + 1; 这样的写法可能无法正确获取进位CF的原因是因为连续赋值语句的执行顺序是从右到左。在这种情况下,a + b 的结果会先计算出来,然后再加上1,最后才赋值给 {CF, res}。
而当你将 B = b + 1; 放在前面,{CF, res} = a + B; 这样的写法可以正确获取进位CF的原因是因为此时 B 的值已经计算出来了,然后才进行 a + B 的运算。
7. Verilator仿真和Vivado仿真的区别
主要有2点:
-
Verilator仿真会将时钟更新的事件插到所有组合逻辑计算完后,再仿真时序逻辑,这和vivado的行为模拟有差别。下面例子中,decoder是组合逻辑,regfile是时序逻辑,在vivado的行为仿真中,对于regfile中的data信号,在时钟上升沿取的wen就是这个上升沿时刻的wen。而在verilator中取的wen是decoder的组合逻辑计算完后的wen。
regfile.v
module regfile( input clk, input rst, input wen, output reg data ); always@(posedge clk) begin if(rst) begin data<=0; end else if(wen) data<=1; else data<=0; end endmodule
decoder.v
module decoder( input wire op, output wire wen ); assign wen=op; endmodule
top.v(此处是在vivado中的仿真文件,在verilator中对于信号的变化是写在c语言中的)
module top( ); reg clk; reg rst; reg op; wire wen; wire data; decoder d_i( .op(op), .wen(wen) ); regfile r_i( .clk(clk), .rst(rst), .wen(wen), .data(data) ); initial begin clk=0; end always #10 clk=~clk; initial begin rst=1; op=0; #10 op=0; rst=0; #10 op=1; end endmodule
-
Verilator仿真若在时钟上升沿处手动调整信号,则上升沿处读入的是调整后的信号