基础数字电路的Verilog写法
Verilog是硬件描述电路,我对此一直稀里糊涂,于是将锆石科技开发板附带的的一些基础数字电路Verilog程序整理记录下来,并且查看他们的RTL视图,总算有点理解了。
1.基本运算符
1 module Example_Operation 2 ( 3 input [3:0] a , 4 input [3:0] b , 5 input [3:0] c , 6 7 output [3:0] c1 , 8 output [3:0] c2 , 9 output [5:0] c3 , 10 output [3:0] c4 , 11 output [3:0] c5 , 12 output [3:0] d1 , 13 output [3:0] d2 , 14 output [3:0] d3 , 15 output [3:0] d4 , 16 output [3:0] e1 , 17 output [3:0] e2 , 18 output [3:0] e3 , 19 output [3:0] f1 , 20 output [3:0] f2 , 21 output [3:0] d11 , 22 output [3:0] c11 , 23 output [3:0] c22 , 24 output [3:0] c33 , 25 output [3:0] c44 , 26 output [3:0] c55 , 27 output [3:0] c66 , 28 output [3:0] e11 , 29 output [3:0] e22 , 30 output [7:0] f11 , 31 output [7:0] f22 32 ); 33 34 //== waveform1 算数运算符 35 //====================================================================== 36 assign c1 = a + b; //加 37 assign c2 = a - b; //减 38 assign c3 = a * b; //乘 39 assign c4 = a / b; //除 40 assign c5 = a % b; //求余 41 42 //== waveform2 关系运算符 43 //====================================================================== 44 assign d1 = a > b; //大于 45 assign d2 = a < b; //小于 46 assign d3 = a >= b; //大于等于 47 assign d4 = a <= b; //小于等于 48 49 //== waveform3 逻辑运算符 50 //====================================================================== 51 assign e1 = !a; //非 52 assign e2 = a && b; //与 53 assign e3 = a || b; //或 54 55 //== waveform4 逻辑等式运算符 56 //====================================================================== 57 assign f1 = a == b; //判断相等 58 assign f2 = a != b; //判断不等 59 60 //== waveform5 三目条件运算符 61 //====================================================================== 62 assign d11 = a ? b : c; //a为真,则d11 = b 63 //a为假,则d11 = c 64 65 //== waveform6 位运算符 66 //====================================================================== 67 assign c11 = ~a; //取反 68 assign c22 = a & b; //按位与 69 assign c33 = a | b; //按位或 70 assign c44 = a ^ b; //按位异或 71 assign c55 = a ~^ b; //按位同或 72 assign c66 = a ^~ b; //按位同或 73 74 //== waveform7 移位运算符 75 //====================================================================== 76 assign e11 = a << b; //左移 77 assign e22 = a >> b; //右移 78 79 //== waveform8 位拼接运算符 80 //====================================================================== 81 assign f11 = {a , b}; //拼接a和b,a和b位宽均为4,f11位宽为8 82 assign f22 = {2'd2{b}}; //拼接b低2位 83 84 endmodule
2.三人表决器 --- 结构描述方式
1 module Example_Structure 2 ( 3 input A , //模块的输入端口A 4 input B , //模块的输入端口B 5 input C , //模块的输入端口C 6 output L //模块的输出端口L 7 ); 8 9 //== 信号定义 10 //====================================================================== 11 wire AB,BC,AC; //内部信号声明AB,BC,AC 12 13 and U1(AB,A,B); //与门(A,B信号进入)(A与B信号即AB输出) 14 and U2(BC,B,C); //与门 同上 15 and U3(AC,A,C); //与门 同上 16 17 or U4(L,AB,BC,AC); //或门 同上 18 19 endmodule
3.三人表决器 --- 数据流描述方式
1 module Example_Dataflow 2 ( 3 input A , //模块的输入端口A 4 input B , //模块的输入端口B 5 input C , //模块的输入端口C 6 output L //模块的输出端口L 7 ); 8 9 assign L = ((!A) & B & C) | (A & (!B) & C) | (A & B & (!C)) | (A & B & C); 10 11 endmodule
4.三人表决器 --- 行为描述方式
1 module Example_Behavior 2 ( 3 input A , //模块的输入端口A 4 input B , //模块的输入端口B 5 input C , //模块的输入端口C 6 output reg L //模块的输出端口L 7 ); 8 9 always @(A,C,B)begin //敏感列表只需要A、B、C,也可以写成always @(*) 10 case({A,B,C}) //注意{A,B,C}是位拼接,合成一条总线 11 3'b000: L = 1'b0; 12 3'b001: L = 1'b0; 13 3'b010: L = 1'b0; 14 3'b011: L = 1'b1; 15 3'b100: L = 1'b0; 16 3'b101: L = 1'b1; 17 3'b110: L = 1'b1; 18 3'b111: L = 1'b1; 19 default:L = 1'bx; //default不要省略 20 endcase 21 end 22 23 endmodule
5.模块化设计实现半加器
1 module Example_Module 2 ( 3 input a , 4 input b , 5 output s , 6 output c 7 ); 8 9 //== 实例化 与门 10 //====================================================================== 11 Example_yumen yumen_module 12 ( 13 .yumen_a(a), 14 .yumen_b(b), 15 .yumen_c(c) 16 ); 17 18 //== 实例化 异或 19 //====================================================================== 20 Example_yihuo yihuo_module 21 ( 22 .yihuo_a(a), 23 .yihuo_b(b), 24 .yihuo_s(s) 25 ); 26 27 endmodule
1 module Example_yihuo 2 ( 3 input yihuo_a , 4 input yihuo_b , 5 output yihuo_s 6 ); 7 8 assign yihuo_s = yihuo_a ^ yihuo_b; 9 10 endmodule
1 module Example_yumen 2 ( 3 input yumen_a , 4 input yumen_b , 5 output yumen_c 6 ); 7 8 assign yumen_c = yumen_a && yumen_b; 9 10 endmodule
6.8-1数据选择器
1 module Digital_Selector 2 ( 3 input D0 , 4 input D1 , 5 input D2 , 6 input D3 , 7 input D4 , 8 input D5 , 9 input D6 , 10 input D7 , 11 input [ 2:0] A , 12 output reg [ 7:0] Y 13 ); 14 15 always @(*)begin 16 case(A) 17 3'b000 : Y = D0; 18 3'b001 : Y = D1; 19 3'b010 : Y = D2; 20 3'b011 : Y = D3; 21 3'b100 : Y = D4; 22 3'b101 : Y = D5; 23 3'b110 : Y = D6; 24 3'b111 : Y = D7; 25 default: Y = 1'b0; 26 endcase 27 end 28 29 endmodule
7.8-3编码器
1 module Digital_Encoder 2 ( 3 input [ 7:0] I , 4 output reg [ 2:0] A 5 ); 6 7 //== case判断I,8位数转为3位数 8 //====================================================================== 9 always @(*)begin 10 case(I) 11 8'b0000_0001 : A = 3'b000; 12 8'b0000_0010 : A = 3'b001; 13 8'b0000_0100 : A = 3'b010; 14 8'b0000_1000 : A = 3'b011; 15 8'b0001_0000 : A = 3'b100; 16 8'b0010_0000 : A = 3'b101; 17 8'b0100_0000 : A = 3'b110; 18 8'b1000_0000 : A = 3'b111; 19 default: A = 3'b000; 20 endcase 21 end 22 23 24 /* 25 //== if...else优先级写法,优先级从上到下 26 //====================================================================== 27 always @(*)begin 28 if(I[7] == 1'b0) A = 3'b000; 29 else if(I[6] == 1'b0) A = 3'b001; 30 else if(I[5] == 1'b0) A = 3'b010; 31 else if(I[4] == 1'b0) A = 3'b011; 32 else if(I[3] == 1'b0) A = 3'b100; 33 else if(I[2] == 1'b0) A = 3'b101; 34 else if(I[1] == 1'b0) A = 3'b110; 35 else if(I[0] == 1'b0) A = 3'b111; 36 else A = 3'b000; 37 end 38 */ 39 40 endmodule
8.3-8译码器
1 module Digital_Decoder 2 ( 3 input [ 2:0] A , 4 output reg [ 7:0] I 5 ); 6 7 always @(*)begin 8 case(A) 9 3'b000 : I = 8'b01111111; 10 3'b001 : I = 8'b10111111; 11 3'b010 : I = 8'b11011111; 12 3'b011 : I = 8'b11101111; 13 3'b100 : I = 8'b11110111; 14 3'b101 : I = 8'b11111011; 15 3'b110 : I = 8'b11111101; 16 3'b111 : I = 8'b11111110; 17 default: I = 8'b11111111; 18 endcase 19 end 20 21 endmodule
9.D触发器
1 module Digital_Data_Flip_Flop 2 ( 3 input clk , 4 input rst_n , 5 input D , 6 output reg Q 7 ); 8 9 always @(posedge clk or negedge rst_n)begin 10 if(!rst_n) 11 Q <= 1'b0; 12 else 13 Q <= D; 14 end 15 16 endmodule
10.4bit移位寄存器
1 module Digital_Shift_Reg 2 ( 3 input clk , 4 input rst_n , 5 input data_in , 6 input data_en , 7 output reg [ 3:0] data_out , 8 output reg [ 3:0] data_out_n 9 ); 10 11 //== 时序逻辑,寄存data_out_n的值,所以看起来比data_out_n慢一拍 12 //====================================================================== 13 always @(posedge clk or negedge rst_n)begin 14 if(!rst_n) 15 data_out <= 4'b0; 16 else 17 data_out <= data_out_n; 18 end 19 20 //== 组合逻辑,不断移位 21 //====================================================================== 22 always @(*)begin 23 if(data_en) 24 data_out_n = {data_out[2:0],data_in}; 25 else 26 data_out_n = data_out; 27 end 28 29 /*---------------------------------------------------------------------- 30 --补充:如果要实现循环右移,则写成[data_in,data_out[3:1]] 31 ----------------------------------------------------------------------*/ 32 33 34 endmodule
11.反馈回环的正误解析
1 //== 错误写法:data_out既是条件又是结果 2 //====================================================================== 3 module Example_Feedback 4 ( 5 input data_in1 , 6 input data_in2 , 7 output data_out 8 ); 9 //data_out是最终结果,可又是形成条件 10 assign data_out = (data_in2) ? data_in1 : (~data_out | data_in1); 11 12 endmodule 13 14 15 /* 16 //== 正确写法:用data_out_r寄存一下,再给data_out 17 //====================================================================== 18 module Example_Feedback 19 ( 20 input clk , 21 input rst_n , 22 input data_in1 , 23 input data_in2 , 24 output data_out 25 ); 26 27 //信号定义 28 reg data_out_r ; 29 30 //时序逻辑,寄存结果 31 always @ (posedge clk or negedge rst_n) 32 begin 33 if(!rst_n) 34 data_out_r <= 1'b0; 35 else 36 data_out_r <= (data_in2) ? (data_in1) : (~data_out_r | data_in1); 37 end 38 39 //寄存后的结果再输出 40 assign data_out = data_out_r; 41 42 endmodule 43 */
12.阻塞赋值和非阻塞赋值
1 module Example_Block 2 ( 3 input clk , 4 input block_in , 5 output block_out1 , 6 output block_out2 , 7 output no_block_out1 , 8 output no_block_out2 9 ); 10 11 //block模块例化 12 block block_init 13 ( 14 .clk (clk ), 15 .block_in (block_in ), 16 .block_out1 (block_out1 ), 17 .block_out2 (block_out2 ) 18 ); 19 20 //no_block模块例化 21 no_block no_block_init 22 ( 23 .clk (clk ), 24 .no_block_in (block_in ), 25 .no_block_out1 (no_block_out1 ), 26 .no_block_out2 (no_block_out2 ) 27 ); 28 29 endmodule
1 module block 2 ( 3 input clk , 4 input block_in , 5 output reg block_out1 , 6 output reg block_out2 7 ); 8 9 always @(posedge clk)begin 10 block_out1 = block_in; 11 block_out2 = block_out1; 12 end 13 14 endmodule
1 module no_block 2 ( 3 input clk , 4 input no_block_in , 5 output reg no_block_out1 , 6 output reg no_block_out2 7 ); 8 9 always @(posedge clk)begin 10 no_block_out1 <= no_block_in; 11 no_block_out2 <= no_block_out1; 12 end 13 14 endmodule
这些基础数字电路的Verilog描述应该非常熟悉,才能够为后面的学习打下扎实的基础。
参考资料:[1]锆石科技FPGA教程