我是靠谱客的博主 知性巨人,这篇文章主要介绍Verilog小总结Verilog小总结,现在分享给大家,希望可以做个参考。

Verilog小总结

基础

assign

assign作为一个组合逻辑常用的语句,可认为是将电线连接起来,当然它能做的不仅仅是将一个输入直接输出,它能把输入信号进行逻辑运算后再输出。当assign左右两边位宽不相等时,将自动进行零扩展或截断以匹配左边的位宽。

eg:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
module top_module ( input a, input b, input c, input d, output out, output out_n ); wire w1, w2; // Declare two wires (named w1 and w2) assign w1 = a&b; // First AND gate assign w2 = c&d; // Second AND gate assign out = w1|w2; // OR gate: Feeds both 'out' and the NOT gate assign out_n = ~out; // NOT gate endmodule

Vectors

声明向量

type [upper:lower] vector_name;
type指定向量的数据类型,通常是wirereg。如果要声明输入或输出端口,则该类型还可以另外包括端口类型(例如,inputoutput

复制代码
1
2
3
4
5
6
7
wire [7:0] w; // 8-bit wire reg [4:1] x; // 4-bit reg output reg [0:0] y; // 1-bit reg that is also an output port (this is still a vector) input wire [3:-2] z; // 6-bit wire input (negative ranges are allowed) output [3:0] a; // 4-bit output wire. Type is 'wire' unless specified otherwise. wire [0:7] b; // 8-bit wire where b[0] is the most-significant bit.

部分选择

使用向量名称访问整个向量,但是当assign左右两边位宽不相等时,将自动进行零扩展或截断以匹配左边的位宽。

使用vector_name[up:low]的形式获取部分向量,注意方向应与定义的一致,如定义了一个a[3:0],那么不能反向获取a[0:3]

矢量运算

  • 位运算
符号功能
~按位取反
&按位与
|按位或
^按位异或
^~按位同或

注意:除了~外均为双目运算符;若进行双目运算时左右两个操作数位数不一样,位数少的将在相应的高位用0扩展。

  • 逻辑运算

逻辑运算会将整个向量视为布尔值(真=非零,假=零),并且产生1位输出,如有input [2:0] ainput [2:0] b 那么他们的逻辑或运算即为assign out = a || b;,a和b均视为一个布尔值。

  • 缩减运算

对一个向量的每一位进行位操作,如有a[2:0],那么b=&a相当于b=(a[0]&a[1])&a[2]

矢量串联

串联运算符{a,b,c}用来将小向量串联起来创建一个更大的向量。**串联中不允许使用不定尺寸的常量。**如{1,2,3}是非法的,因为Verilog不知道他们的位宽。

还可以用{n{vec}}的形式来复制向量,如{6{a}}{a,a,a,a,a,a}是一样的,同时注意两组大括号都是必须的,即{1'b1,6{1'b0}}是非法的,因为其中的6{1'b0}少了一组大括号,正确的写法是{1'b1,{6{1'b0}}}。这其实比较好理解,串联运算符{a,b,c}中的abc均为一个向量,{n{vec}}也代表了一个向量,因此{a,b,{n{c}}}也是一个向量

模块

mod_name instance_name (signal_name1,signal_name2,signal_name3);//by position

mod_name instance_name (.port_name1(signal_name1),.port_name2(signal_name2),.port_name3(signal_name3));//by name

可以理解为一个函数,注意括号内的是外部连接到模块的信号。

always块

组合逻辑

使用always @(*)可以类似于assign的效果,当右方有变量发生改变时,左边输出随之立即改变。assign out1 = a & b | c ^ d;always @(*) out2 = a & b | c ^ d;是一样的

时序逻辑

  • 同步与异步复位
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
//同步复位 always @(posedge clk) begin if(reset == 1) begin //reset end end //异步复位 always @(posedge clk,posedge areset) begin if(areset == 1) begin //reset end end
  • 阻塞赋值非阻塞赋值

一般来说,我们在组合逻辑的always块中使用阻塞赋值(x = y;);在时序逻辑的always块中使用非阻塞赋值(x <= y;

case

复制代码
1
2
3
4
5
6
7
8
9
10
always @(*) begin //这是一个组合逻辑 case (in) 1'b1: begin out = 1'b1; end 1'b0: out = 1'b0; default: out = 1'bx; endcase //一定记得写endcase end

注意一定要写endcase

另外还有case的好兄弟casez,他可以匹配形如4'bzzz1的向量,z表示无关位。

eg:优先编码器

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
module top_module ( input [7:0] in, output reg [2:0] pos ); always @(*) begin casez (in) 8'bzzzzzzz1 : pos = 0; 8'bzzzzzz1z : pos = 1; 8'bzzzzz1zz : pos = 2; 8'bzzzz1zzz : pos = 3; 8'bzzz1zzzz : pos = 4; 8'bzz1zzzzz : pos = 5; 8'bz1zzzzzz : pos = 6; 8'b1zzzzzzz : pos = 7; default: pos =0; endcase end endmodule

for

组合for循环

与C语言的用法类似。

eg:人口计数器

复制代码
1
2
3
4
5
6
7
8
9
10
11
module top_module ( input [254:0] in, output reg [7:0] out ); always @(*) begin //组合逻辑always块 out = 0; //一定要初始化为0 for (int i=0;i<255;i++) out = out + in[i]; end endmodule

生成for循环

当对矢量中多个位进行重复操作时,或进行多个模块的实例化引用的重复操作时,可使用生成块简化程序。写法如下

复制代码
1
2
3
4
5
6
7
genvar i;//只能用genvar作为循环变量 generate for (i=1;i<99;i=i+1) begin: add_loop//这个名字是必须的 mod_name instance_name(......);//括号里写由i推出的信号 end endgenerate

eg:Bcdadd100

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
module top_module( input [399:0] a, b, input cin, output cout, output [399:0] sum ); genvar i; wire [99:0]cout1; bcd_fadd mod1(a[3:0],b[3:0],cin,cout1[0],sum[3:0]); generate for (i=1;i<99;i=i+1) begin: addloop bcd_fadd mod2(a[(4*i+3):(4*i)],b[(4*i+3):(4*i)],cout1[i-1],cout1[i],sum[(4*i+3):(4*i)]); end endgenerate bcd_fadd mod3(a[399:396],b[399:396],cout1[98],cout,sum[399:396]); endmodule

状态机写法

Moore型

三段式写法:使用一个state用于存当前状态,使用一个next_state用于存下一状态。第一段用于写状态转换逻辑,第二段用于状态转移,第三段用于输出。

复制代码
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
reg state, next_state; //第一段: always @(*) begin //一个组合逻辑always块,用于写状态转换逻辑,当in改变时,next_state将立即改变。 case(state) A: next_state = f(in)//关于in的函数 B: next_state = f(in) ... endcase end //第二段(异步): always @(posedge clk, posedge areset) begin if(areset == 1) begin state <= 0;//reset end else state <= next_state; end //第二段(同步): always @(posedge clk) begin if(reset == 1) begin state <= 0;//reset end else state <= next_state; end //第三段(assign法) assign out = (state == ...);//判断state //第三段(组合逻辑always块法) always@(*) begin case (state) A: {out3,out2,out1} = 3'b111; B: {out3,out2,out1} = 3'b110;//对每一种状态输出 ... endcase end

Mealy型

仅仅第三段发生了改变,可使用{state,in}来做输出判断。

复制代码
1
2
3
4
5
6
7
8
9
10
//第三段(assign法) assign out = f(state,in);//关于state和in的函数 //第三段(组合逻辑always块法) always@(*) begin case ({state,in}) 4'b0000: {out3,out2,out1} = 3'b111; 4'b0001: {out3,out2,out1} = 3'b110;//对每一种state与in做输出 ... end

(希望明天P1能过呜呜呜

最后

以上就是知性巨人最近收集整理的关于Verilog小总结Verilog小总结的全部内容,更多相关Verilog小总结Verilog小总结内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(83)

评论列表共有 0 条评论

立即
投稿
返回
顶部