ysyx:0008:verilog & use of verilator

Jackcui NJU Loser

操作符和表达式

  • 同类型操作符之间,除条件操作符从右往左关联,其余操作符都是自左向右关联。圆括号内表达式优先执行。
    对变量进行声明时,要根据变量的操作符对变量的位宽进行合理声明,不要让结果溢出。上述例子中,相加的 2 个变量位宽为 4bit,那么结果寄存器变量位宽最少为 5bit。否则,高位将被截断,导致结果高位丢失。无符号数乘法时,结果变量位宽应该为 2 个操作数位宽之和。
  • 负数表示时,可以直接在十进制数字前面增加一个减号 -,也可以指定位宽。因为负数使用二进制补码来表示,不指定位宽来表示负数,编译器在转换时,会自动分配位宽,从而导致意想不到的结果。
  • 算术操作符如果操作数某一位为 X,则计算结果也会全部出现 X。
  • 关系操作符的正常结果有 2 种,真(1)或假(0)。
  • 如果操作数中有一位为 x 或 z,则关系表达式的结果为 x。
  • 等价操作符包括逻辑相等(==),逻辑不等(!=),全等(===),非全等(!==)。
    等价操作符的正常结果有 2 种:为真(1)或假(0)。
    逻辑相等/不等操作符不能比较 x 或 z,当操作数包含一个 x 或 z,则结果为不确定值。
    全等比较时,如果按位比较有相同的 x 或 z,返回结果也可以为 1,即全等比较可比较 x 或 z。所以,全等比较的结果一定不包含 x。

编译指令(类似于宏定义)

Runoob

时延和时序控制

关于显示指定的时间和Setuptime
关于时延控制和触发

过程结构

所有结构正常情况下相互并行(各自产生独立的控制流)
initial 只进行一次
always 重复进行
更多时候,在设计电路时,always 时序逻辑块中多用非阻塞赋值,always 组合逻辑块中多用阻塞赋值;在仿真电路时,initial 块中一般多用阻塞赋值。
一个避免时序冒险的例子
顺序块 begin…end
并行块 fork…join
命名块(可以相互控制和访问)

disable 在 always 或 forever 块中使用时只能退出当前回合,下一次语句还是会在 always 或 forever 中执行。因为 always 块和 forever 块是一直执行的,此时的 disable 有点类似 C 语言中的 continue 功能。

控制流

condition
loop
assign

其他注意事项

语法正确的代码并不一定能产生功能正常的电路,一般来说都是因为不小心引入了锁存器造成的。如上述例子所示,除了指定的情况外(cpu_overheated),还有一些其它情况,这时会发生什么?在 verilog 中,其结果就是保持不变,这意味着要记住当前状态,从而产生了锁存。

使用case实现组合逻辑时,必须有default,以防出现锁存器

Reference

Runoob

未解之谜

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
module my_dff8(
input clk,
input [7:0] d,
output reg [7:0] q
);
always@(posedge clk)
q <= d;
endmodule

module MUX4(input [7:0]_0, input [7:0]_1, input [7:0]_2, input [7:0]_3, input [1:0] sel, output reg [7:0]out);
always @(*) begin
case(sel)
2'b00: out<=_0;
2'b01: out<=_1;
2'b10: out<=_2;
2'b11: out<=_3;
endcase
end
endmodule

module top_module(
input clk,
input [7:0] d,
input [1:0] sel,
output reg [7:0] q
);
wire [7:0]w[4];
wire [7:0]w01;
wire [7:0]w12;
wire [7:0]relay;
MUX4 mux(w[0],w[1],w[2],w[3],sel,relay);
my_dff8 dff0(clk,d,w01);
my_dff8 dff1(clk,w01,w12);
my_dff8 dff2(clk,w12,w[3]);
assign w[2]=w12;
assign w[1]=w01;
assign w[0]=d;
always @(*) begin
q=relay;
end
endmodule

为什么必须要用线网relay一下???

在设计Verilog模块时,请遵循以下原则:
在组合逻辑的always块内采用阻塞赋值
时序逻辑的always块内采用非阻塞赋值
违背这一原则将可能导致难以发现的电路错误,且可能导致仿真与综合的不一致,请用户切记。至于为何这样,初学者可以不必理会,简单理解为verilog语法规范性要求即可。
不初学呢???

还有一个题不知道为什么WA了

模块库

D_flip-flop
1
2
3
4
module dff(input clk,input d,output reg q);
always@(posedge clk)
q <= d;
endmodule
adder
1
2
3
module add16 ( input[15:0] a, input[15:0] b, input cin, output[15:0] sum, output cout );
assign {cout,sum} = a + b + cin;
endmodule
  • Post title:ysyx:0008:verilog & use of verilator
  • Post author:Jackcui
  • Create time:2023-08-19 11:18:23
  • Post link:https://jackcuii.github.io/2023/08/19/ysyx0008/
  • Copyright Notice:All articles in this blog are licensed under BY-NC-SA unless stating additionally.
 Comments