verilog基础运算——拼接运算、全加器、阻塞与非阻塞、D触发器、移位寄存器、8-3编码器、3-8解码器等

1、verilog位拼接运算符

位拼接运算符定义和tb仿真

  • 在Verilog HDL语言有一个特殊的运算符:位拼接运算符 {},它可以把两个或多个信号的某些位拼接起来进行运算操作。

如下是位拼接运算的例子以及tb仿真:

 module Example_Operation(a,b,f11,f22);
 
	    input  [3:0]         a     ;
	    input  [3:0]         b     ;
	    output [7:0]        f11     ;
	    output [5:0]        f22     ;
	    
  assign f11 = {a , b};   //拼接a和b,a和b位宽均为4,f11位宽为8
  assign f22 = {2'd2{b}}; //拼接b低2位
  
endmodule 

testbench测试:

`timescale 1ns/1ps //时间精度
`define Clock 20 //时间周期

module Example_Operation_tb;
//端口
		reg [3:0] a,b; 

		wire [7:0] f11; 
		wire [5:0] f22; 

Example_Operation u2 (
            .a(a),
			.b(b),
			.f11(f11) ,
			.f22(f22)
);

initial begin
        a=0000;b=0000;
        #(`Clock*20);
  		a=0001;b=1000;
		#(`Clock*20);
  		a=1000;b=0101;
		#(`Clock*20);
  		a=1010;b=1001;
		#(`Clock*20);
  		a=1011;b=1111;
end
endmodule

在这里插入图片描述
由图可以看出,f22是拼接b低2位,将b低2位作为高位,后面拼接b

2、三人表决器

确定输入输出以及真值表

根据真值表写出输出表达式

根据表达式得到逻辑电路图

  • 三个输入,可分别设为a,b,c,输出设为 I

  • 写真值表:

abcI
0000
0010
0100
0111
1000
1011
1101
1111

-根据真值表写出输出表达式:
在这里插入图片描述
化简:
在这里插入图片描述

-得到逻辑电路:
在这里插入图片描述

module Example_Structure(a,b,c,l);
 
    input a,b,c;
	output l;
	assign l = ((a&&b)||(b&&c)||(a&&c));

endmodule

testbench测试:

module Example_Structure_tb;
    reg a,b,c;
	wire l;
Example_Structure u1 (
        .a(a),
		.b(b),
		.c(c),
		.l(l)
);

initial begin
        #(`Clock*20);
        a=0;b=0;c=0;
        #(`Clock*20);
  		a=0;b=0;c=1;
		#(`Clock*20);
  		a=0;b=1;c=0;
		#(`Clock*20);
		a=0;b=1;c=1;
		#(`Clock*20);
  		a=1;b=0;c=0;
		#(`Clock*20);
  		a=1;b=0;c=1;
		#(`Clock*20);
		a=1;b=1;c=0;
		#(`Clock*20);
		a=1;b=1;c=1;
		#(`Clock*20);
		$stop;
end

endmodule
		

在这里插入图片描述

3、半加器

半加器是对两个一位二进制数进行相加,产生“和”、“进位”。

确定输入和输出后写真值表

根据真值表得到输出表达式

  • 真值表:
absc
0000
0110
1010
1111

-根据真值表得到输出表达式:

s=a^b    c=a&b

-逻辑电路:
在这里插入图片描述

  module halfadder(a,b,c,s);
	    input a,b;
		output  s;
		output c;
		
		assign s=a^b;
	    assign c=a&b;
 
 endmodule 

testbench测试:

`timescale 1ns/1ps //时间精度
`define Clock 20 //时间周期

module halfadder_tb;
//端口

	reg         a    ; 
	reg         b    ; 	
    wire        s    ;
    wire        c    ; 
		
halfadder u2 (
            .a(a),
			.b(b),
			.s(s),
			.c(c) 
);

initial begin

        a=0;b=0;
        #(`Clock*20);
  		a=0;b=1;
		#(`Clock*20);
  		a=1;b=0;
		#(`Clock*20);
  		a=1;b=1;
		#(`Clock*20);
		$stop;
end

endmodule

在这里插入图片描述
采用模块化RTL的方式进行设计

在这里插入图片描述

top顶层模块:

module Example_module
 (
     input       a       ,
     input       b       ,
     output      s       ,
     output      c
 );
 

Example_yumen   yumen_module 
 (
     .yumen_a(a),
     .yumen_b(b),
     .yumen_c(c)
 );
 
 Example_yihuo yihuo_module
 (
     .yihuo_a(a),
     .yihuo_b(b),
     .yihuo_s(s)
 );
 
 endmodule

分层小模块 c1:

module  Example_yumen(yumen_a,yumen_b,yumen_c);
 
  input  yumen_a,yumen_b;
  output yumen_c;
 
  assign yumen_c=yumen_a&yumen_b;
 
 endmodule 

分层小模块 c2:

  module Example_yihuo(yihuo_a,yihuo_b,yihuo_s);
    
     input  yihuo_a,yihuo_b;
     output yihuo_s;
 
 assign yihuo_s=yihuo_a^yihuo_b;
 
 endmodule 

4、全加器

全加器是实现两个一位二进制数相加的基本单元,其内部主要由 n 个全加器构成。 设Ai为被加数,Bi为加数,本位和Si,高位进位Ci,低位进位Ci-1

Ci-1AiBiSiCi
00000
00110
01010
01101
10010
10101
11001
11111

得到输出表达式:
在这里插入图片描述

逻辑电路:

在这里插入图片描述

硬件描述:

 module fulladder(a,b,Ci,Si,C_out);

    input a,b,Ci;
	output Si,C_out;
	
    assign Si=a^b^Ci;
    assign C_out=((a&b)| (Ci&(a^b)));

endmodule 

testbench测试:

`timescale 1ns/1ps //时间精度
`define Clock 20 //时间周期

module fulladder_tb;
//端口

reg a,b,Ci         ; 

wire       Si      ;
wire       C_out   ; 
	
fulladder u2 (
                .a(a),
				.b(b),
				.Ci(Ci),
				.Si(Si) ,
				.C_out(C_out) 
);

initial begin

    a=0;b=0;Ci=0;
    #(`Clock*20);
	a=0;b=0;Ci=1;
	#(`Clock*20);
	a=0;b=1;Ci=0;
	#(`Clock*20);
	a=0;b=1;Ci=1;
	#(`Clock*20);
	a=1;b=0;Ci=0;
	#(`Clock*20);
	a=1;b=0;Ci=1;
	#(`Clock*20);
	a=1;b=1;Ci=0;
	#(`Clock*20);
	a=1;b=1;Ci=1;
	#(`Clock*20);
	$stop;
end

endmodule

在这里插入图片描述

5、数据选择器

经过选择,把多个通道的数据传到唯一的公共数据通道上。

在这里插入图片描述

module Digital_Selector(sel,D0,D1,D2,D3,Y);
   
      input [1:0] sel;
      input [7:0] D0,D1,D2,D3;
      output reg [7:0] Y;      //Y为reg型
  
  always @(*)begin    //电平触发

     case (sel) 
	     2'b00:Y=D0;
		 2'b01:Y=D1;
         2'b10:Y=D2;
		 2'b11:Y=D3;	 
      default : Y = 1'b0;
    endcase
  end
endmodule 

testbench测试:

`timescale 1ns/1ps //时间精度
`define Clock 20 //时间周期

module Digital_Selector_tb;
//端口

	 reg [1:0]sel;
	 reg [7:0] D0,D1,D2,D3;

     wire  [7:0] Y ;
    		
Digital_Selector u2 (
            .sel(sel),
				.D0(D0),
				.D1(D1),
				.D2(D2),
				.D3(D3),
				.Y(Y) 
  );
initial begin
   sel=2'b00;  
   D0= 00000000;
   D1= 00000001;
   D2= 00000010;
   D3= 00000100;
   #(`Clock*20);
   
  sel=2'b01;    
	D0 = 00000000;
    D1 = 00000001;
    D2 = 00000010;
    D3 = 00000100;
	#(`Clock*20);

  sel=2'b10;
	D0 = 00000000;
    D1 = 00000001;
    D2 = 00000010;
    D3 = 00010100;
	#(`Clock*20);
	
sel=2'b00;
	D0 = 00010000;
    D1 = 00000001;
    D2 = 00000010;
    D3 = 00000100;
	
	#(`Clock*20);
sel=2'b11;
	D0 = 00000000;
    D1 = 00000001;
    D2 = 00000010;
    D3 = 00000100;
	#(`Clock*20);
sel=2'b00;
	D0 = 00000000;
    D1 = 00000001;
    D2 = 00000010;
    D3 = 00000100;
	#(`Clock*20);
sel=2'b10;
	D0 = 00000000;
    D1 = 00000001;
    D2 = 00000010;
    D3 = 00000100;
	#(`Clock*20);
	$stop;
end

endmodule

在这里插入图片描述

6、8-3编码器

编码器(encoder)是将信号(如比特流)或数据进行编码
在这里插入图片描述
8-3编码器真值表:
在这里插入图片描述
得到输出表达式:
在这里插入图片描述

module Digital_Encoder
(
    input      [ 7:0]   I               ,
    output reg [ 2:0]   A
);

always @(*)begin
    case(I)
        8'b00000001 : A = 3'b000;
        8'b00000010 : A = 3'b001;
        8'b00000100 : A = 3'b010;
        8'b00001000 : A = 3'b011;
        8'b00010000 : A = 3'b100;
        8'b00100000 : A = 3'b101;
        8'b01000000 : A = 3'b110;
        8'b10000000 : A = 3'b111;
        default     : A = 3'b000;
    endcase
end
endmodule 

testbench测试:

`timescale 1ns/1ps //时间精度
`define Clock 20 //时间周期

module Digital_Encoder_tb;
    reg [7:0]I      ; 
    wire  [2:0] A   ; 
		
Digital_Encoder u2 (
                           .I(I),
			               .A(A)
);	

initial begin

    I=00000000;
    #(`Clock*20);
	I=00000001;
	#(`Clock*20);
	I=00000010;
	#(`Clock*20);
	I=00000011;
	#(`Clock*20);
	I=000000100;
	#(`Clock*20);
	I=00010000;
	#(`Clock*20);
	I=01100000;
	#(`Clock*20);
	I=00000000;
	#(`Clock*20);
	I=1000000;
	#(`Clock*20);
	I=01000000;
	#(`Clock*20);
	I=00100000;
	#(`Clock*20);
	I=00010000;
	#(`Clock*20);
	I=00001000;
	#(`Clock*20);
	I=0000010;
	#(`Clock*20);
	$stop;
end
endmodule

在这里插入图片描述

7、3-8解码器

三位输入,通过解码器,得到对应的八位输出。

module Decoder0(

    input [2:0] I,
    output reg [7:0] O 

);

always@(*)  begin
    case(I)
        3'b000 : O = 8'b0000_0001;
        3'b001 : O = 8'b0000_0010;
        3'b010 : O = 8'b0000_0100;
        3'b011 : O = 8'b0000_1000;
        3'b100 : O = 8'b0001_0000;
        3'b101 : O = 8'b0010_0000;
        3'b110 : O = 8'b0100_0000;
        3'b111 : O = 8'b1000_0000;
        default: O = 8'b0000_0000;     
    endcase

end

endmodule 

RTL图:
在这里插入图片描述


`timescale 1ns/1ps //时间精度
`define Clock 20

module Decoder0_tb;

		reg [2:0] I;
		wire [7:0] O; 

Decoder0 inst_Decoder0 (
	
	.I(I), 
	.O(O)
	
);

initial begin
   I = 3'b000 ;
	#(`Clock*20);
   I = 3'b001 ;
	#(`Clock*20);
	I = 3'b100 ;
	#(`Clock*20);
   I = 3'b110 ;
	#(`Clock*20);	
   I = 3'b111 ;
	#(`Clock*20);
   I = 3'b011 ;	
	#(`Clock*20);	
   #(`Clock*150);
   $stop;
end	

endmodule

波形如下:
在这里插入图片描述

8、D触发器

在这里插入图片描述
边沿触发方式:

边沿触发:输出只要在时钟边沿的时候才能发生改变,否则保持不变。

电平触发:

触发信号为有效电平(高或低)时,输出随输入变化,否则保持。

  module Digital_Data_Flip_Flop(D,CLK,rst_n,Q);    //数据数字触发器

  input D;
  input CLK,rst_n;
  
  output reg Q;
  
  always @(posedge CLK or negedge rst_n)begin
		
		if(!rst_n)
		         Q <= 1'b0;
        else 
                 Q <= D;
 end 	 
endmodule 

RTL图:
在这里插入图片描述

testbench测试:

`timescale 1ns/1ps //时间精度
`define Clock 20 //时间周期
	
	module Digital_Data_Flip_Flop_tb;
	  reg D;
	  reg CLK,rst_n;  
	  wire Q;
	  
	Digital_Data_Flip_Flop u1(
	        .D(D),
			.CLK(CLK),
			.rst_n(rst_n),
			.Q(Q)
 	);
			
	initial begin
	    CLK = 0;
	    forever #(`Clock/2) CLK = ~CLK;
	end
	
	initial begin
	   rst_n=0; #(`Clock*20+1);
	   rst_n=1;
	end	
	
	initial begin
	     D=1'b0;#(`Clock*20);
		  D=1'b1;#(`Clock*20);
		  D=1'b1;#(`Clock*20);
		  D=1'b0;#(`Clock*20);
		  D=1'b1;#(`Clock*20);
		  D=1'b0;#(`Clock*20);
		  D=1'b0;#(`Clock*20);
		  D=1'b1;#(`Clock*20);
		  $stop;
	end
	endmodule 

波形可看到,上升沿的时候Q变化
在这里插入图片描述

9、4bit移位寄存器

4个边沿D触发器构成4位移位寄存器

 module Digital_Shift_Reg	(
	 
	    input               clk         ,
	    input               rst_n       ,
	    input               data_in     ,
	    input               data_en     ,
	    output reg [ 3:0]   data_out    ,
	    output reg [ 3:0]   data_out_n
	);
	

	
//组合逻辑,不断移位
	always @(*)begin
	    if(data_en)
	        data_out_n = {data_in,data_out[3:1]};
	    else
	        data_out_n = data_out;
	end
	
//时序逻辑,寄存data_out_n的值,可以比data_out_n慢一拍
//寄存器输出
	always @(posedge clk or negedge rst_n)begin
	    if(!rst_n)
	        data_out <= 4'b0;
	    else
	        data_out <= data_out_n;
	end
	endmodule

RTL:

在这里插入图片描述

testbench测试:

`timescale 1ns/1ps 
`define Clock 20
 
module Digital_Shift_Reg_tb;

      reg clk,rst_n;
      reg data_en;
      reg  data_in;
  
      wire [3:0] data_out_n;
      wire [3:0] data_out;

Digital_Shift_Reg u1(
         .clk(clk),
		 .rst_n(rst_n),
		 .data_en(data_en),
		 .data_in(data_in),
		 .data_out(data_out),
		 .data_out_n(data_out_n)
);

initial clk=0;
    always #(`Clock/2) clk = ~clk;
	 
initial begin
     rst_n = 0;
	 data_in= 0;
	 data_en=0;

	 #(`Clock+1)
	 rst_n = 1;
	 data_en=1;
	 data_in= 1;
	 
	 #1000
	 $stop;
end
endmodule  

在这里插入图片描述

10、阻塞赋值“=”(组合逻辑电路),非阻塞赋值“<=”(时序逻辑电路)

  • 阻塞

"阻塞"当前的赋值语句阻断了其后的语句,也就是说后面的语句必须等到当前的赋值语句执行完毕才能执行

  • 非阻塞

“非阻塞”是当前的赋值语句不会阻断其后的语句。非阻塞语句可以认为是分为两个步骤进行的,非阻塞赋值操作只能用于对寄存器类型变量进行赋值

  • 加入延迟
    向assign连续赋值语句以及过程赋值语句always中加入delay,都会被综合器忽视。如下:
assign #2 Out = ~In; //assign语句中的延迟
#5 RegB  <= RegA ;  //always块非阻塞语句中的延迟
Reg = #2 RegA  ;//always块阻塞语句中的延迟

题目1:答案 0 2
在这里插入图片描述
这里可直接画出对应的电路更好理解:
左边:
在这里插入图片描述

右边:
在这里插入图片描述


题目2:
如果我们用阻塞和非阻塞两种方式实现非门,RTL如下:

阻塞:生成门电路
在这里插入图片描述
非阻塞:生成寄存器
在这里插入图片描述


对阻塞赋值和非阻塞赋值进行仿真验证

top顶层设计:

module Example_Block(clk,block_in,no_block_out1,no_block_out2,block_out1,block_out2);
	
   	  input clk;
	  input block_in;
	 
  	  output no_block_out1;
	  output no_block_out2;
	  output block_out1;
	  output block_out2;
	 
	 //block模块例化
	 block block_init //阻塞赋值
	 (
	     .clk               (clk         ),
	     .block_in          (block_in    ),
	     .block_out1       (block_out1    ),
	     .block_out2       (block_out2    )
	 );
	 
	 //no_block模块例化
	 no_block no_block_init //非阻塞赋值
	 (
	     .clk            (clk            ),
	     .no_block_in    (block_in        ),
	     .no_block_out1    (no_block_out1    ),
	     .no_block_out2    (no_block_out2    )
	 );
	endmodule 
//分层模块 c1阻塞赋值 :
		
	 module block
		 (
		     input        clk         ,
		     input        block_in    ,
		     output reg  block_out1  ,
		     output reg  block_out2
		 );
		 
		 always @(posedge clk)begin   
		     block_out1 = block_in;
		     block_out2 = block_out1; //相当于组合逻辑,因此不会产生clk延迟
		 end
		 
	 endmodule

//分层模块 c2非阻塞赋值:
module no_block
(
    input        clk             ,
    input        no_block_in     ,
    output reg  no_block_out1   ,
    output reg  no_block_out2
);

always @(posedge clk)begin 
    no_block_out1 <= no_block_in;
    no_block_out2 <= no_block_out1; //生成寄存器,因此out2会下一clk接收
end

endmodule

在这里插入图片描述

  • 3
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Fighting_FPGA

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值