Verilg代码题——复杂电路设计1

1 篇文章 0 订阅

复杂电路设计-1

二进制转格雷码&格雷码转二进制

二进制转格雷码

module dual2gray
    (input [3:0] dual_data,
    output [3:0] gray_data);

    assign gray_data[0] = dual_data[0] ^ dual_data[1] ;
    assign gray_data[1] = dual_data[1] ^ dual_data[2] ;
    assign gray_data[2] = dual_data[2] ^ dual_data[3] ;
    assign gray_data[3] = dual_data[3] ;

endmodule

格雷码转二进制

module gray2dual
    (input [3:0] gray_data,
    output [3:0] dual_data);

    assign dual_data[0] = gray_data[0] ^ gray_data[1] ^ gray_data[2] ^ gray_data[3] ;
    assign dual_data[1] = gray_data[1] ^ gray_data[2] ^ gray_data[3] ;
    assign dual_data[2] = gray_data[2] ^ gray_data[3] ;
    assign dual_data[3] = gray_data[3] ;

endmodule

二进制转BCD

在这里插入图片描述
算法:加三移位法
二进制满16进一
十进制满10进一
将二进制>=10的数+6,会产生进位,进位分别代表十位的高一位,本位数据和高位数据表示原始值

module bi2BCD(
	input [7:0] d_in,
    output [11:0] d_out);
    
    reg [3:0] ge,shi,bai;
    reg [11:0] d_mid;
    
    integer i;
    always@(*) begin
        {bai,shi,ge} = 'b0;
        for(i = 7;i >= 0;i = i-1)
        begin
        if( ge > 4 ) begin
            {shi,ge} = {shi,ge} + 3;
            end
        else if (shi > 4 ) begin
            {bai,shi} = {bai,shi} + 3;
            end
        else begin
            {bai,shi,ge} = {bai,shi,ge};
        end
        d_mid = {bai,shi,ge};//最后将d_in[0]输入后结束
        {bai,shi,ge} = { d_mid[10:0] , d_in[i] };
        end
    end
    assign d_out = {bai,shi,ge};
endmodule

Testbench

module inst_tb();

    reg  [7:0] d_in;
    wire  [11:0] d_out;
    
    initial
    begin
    d_in = 8'hff;
    #10
    d_in = 8'h23;
    #10
    d_in = 8'ha2;
    end
    
    inst bi2BCD(.d_in(d_in),.d_out(d_out));
    
endmodule

在这里插入图片描述

秒计数器设计

//系统时钟:10MHz,T为100ps
//基于系统时钟的计数:cont_t(计数范围0-10000000-1),每循环一圈就是1秒。
//秒脉冲:触发器,每看到0就置为1,不是0就置为0,就可以得到一秒一个脉尖冲,称为秒脉冲
//秒计数:对秒脉冲进行计数,看到一个秒脉尖冲加一。(9加1变成0)

module Timer (
    input clk;//24MHz
    input reset_n
    
    output se
);
	reg [31:0] cont_t;
    always@(posedge clk)
    begin
	    if(!reset_n) begin
	    cont_t <= 1;
	    end
	    else begin
	    cont_t <= cont_t + 1;
	    end
    end
	assign se = (cont_t==32'b0)? 1'b1:1'b0;

endmodule

线性反馈移位寄存器LFSR

原理参考:https://zhuanlan.zhihu.com/p/366067972
线性反馈移位寄存器(LFSR)的英文全称为:Linear Feedback Shift Register。
LFSR由触发器构成,占用资源相对较少,且可以在FPGA内部以很高的时钟速率运行。
可应用于:
(1)计数器(Counters)
(2)测试码型发生器(Test Pattern Generators)
(3)数据加扰(Data Scrambling)
(4)密码学(Cryptography)

运行LFSR时,由各个触发器生成的模式是伪随机的,这意味着它接近随机。 它不是完全随机的,因为从LFSR模式的任何状态,您都可以预测下一个状态。 有一些重要的移位寄存器属性需要注意:
LFSR模式是伪随机的。
输出模式是确定性的。 可通过XOR门的位置以及当前模式来确定下一个状态。

当抽头使用XOR门时,全0的模式不会出现。 由于0与0异或将始终产生0,因此LFSR将停止运行。
当抽头使用XNOR门时,全1的模式将不会出现。 由于将1与1进行异或运算将始终产生1,因此LFSR将停止运行。
任何LFSR的最大可能迭代次数= 2^Bits-1

LFSR的反馈函数就是简单地对移位寄存器中的某些位进行异或,并将异或的结果填充到LFSR的最左端,如图所示。对于LFSR中每一位的数据,可以参与异或,也可以不参与异或。其中,我们把参与异或的位称为抽头。

//以x8+x4+x3+x2+1为例:参与异或的寄存器为:[7],[3],[2],[1]
module m_LFSR(
    input        clk,
    input        rst_n,
    output  reg  [7:0]    m_seq
);
	wire d;
	assign d=m_seq[7]^m_seq[3]^m_seq[2]^m_seq[1];
	always@(posedge clk or negedge rst_n)
	begin
		if (!rst_n)
			m_seq<=8'hff;
		else
			m_seq<={d,m_seq[6:0]};
	end
	endmodule
		

4位超前进位加法器

在这里插入图片描述
在这里插入图片描述
根据全加器进行推导:
输入:a,b,c;输出:c_out,sum
c_out = ab | bc | ac = ab + (a + b) c = ab + (a ^ b) c
sum = a ^ b ^ c;
所以
进位产生函数是:G = ab
进位传输函数是:P = a ^ b

module four_bits_fast_adder(
		input [3:0] a,
		input [3:0] b,
		input c_in,
		output [3:0]sum_out,
		output c_out);
		//wire c1,c2,c3;
		assign c1	 = ( a[0]&b[0] )|( ( a[0]^b[0] ) &c_in) ;
		assign c2	 = ( a[1]&b[1] )|( ( a[1]^b[1] ) &c1);
		assign c3	 = ( a[2]&b[2] )|( ( a[2]^b[2] ) &c2);
		assign c_out = ( a[3]&b[3] )|( ( a[3]^b[3] ) &c3);
	
		assign sum_out[0]=(a[0]^b[0])^c_in;
		assign sum_out[1]=(a[1]^b[1])^c1;
		assign sum_out[2]=(a[2]^b[2])^c2;
		assign sum_out[3]=(a[3]^b[3])^c3;
endmodule

加法器树乘法器

在这里插入图片描述

module mul_addtree(
	input [3:0] mul_a,mul_b,
	output [7:0] mul_out);
	
	wire [3:0] stored0;
	wire [5:0] stored1;
	wire [6:0] stored2;
	wire [7:0] stored3;
	
	assign stored0 = {4{mul_a[0]}} & mul_b;
	assign stored1 = (mul_a[1])? ( mul_b )<<1 : 'b0;//判断存不存在数据丢失情况
	assign stored2 = (mul_a[2])? ( mul_b )<<2 : 'b0;
	assign stored3 = (mul_a[3])? ( mul_b )<<3 : 'b0;
	assign mul_out = stored0 + stored1 +stored2 +stored3;
	
endmodule
	

流水线结构

在这里插入图片描述
流水线就是在每一级组合逻辑中间加入触发器/寄存器组来暂存上一级产生的值,可提高相关电路的处理速度。

module mul_addtree_2_stage(
	input clk,rst_n,
	input [3:0] mul_a,mul_b,
	output  [7:0] mul_out);
	wire [3:0] stored0;
	wire [5:0] stored1;
	wire [6:0] stored2;
	wire [7:0] stored3;
	
	//流水线,触发器组暂存中间值
	wire [7:0] add_tmp_1,add_tmp_2,mul_tmp;
	reg [7:0] add_tmp_1_reg,add_tmp_2_reg,mul_tmp_reg;
	
	//combinatorial logic
	assign stored0 = {4{mul_a[0]}} & mul_b;
	assign stored1 = (mul_a[1])? ( {4{mul_a[1]}} & mul_b )<<1 : 'b0;
	assign stored2 = (mul_a[2])? ( {4{mul_a[2]}} & mul_b )<<2 : 'b0;
	assign stored3 = (mul_a[3])? ( {4{mul_a[3]}} & mul_b )<<3 : 'b0;

	assgin add_tmp_1 = stored0 + stored1;
	assign add_tmp_2 = stored2 + stored3;
	assign mul_tmp   = add_tmp_1 + add_tmp_2;
	
	//sequential logic
	always@(posedge clk)
	begin
		if (!rst_n)
			add_tmp_1_reg <= 'b0;
			add_tmp_2_reg <= 'b0;
			mul_tmp_reg <= 'b0;
		else
			add_tmp_1_reg <= add_tmp_1;
			add_tmp_2_reg <= add_tmp_2;
			mul_tmp_reg <= mul_tmp;
	end

	assign mul_out = mul_tmp_reg;
	
endmodule

向量点积乘法器

采用模块层次化设计方法,设计4维向量点积乘法器,其中向量a = (a1 , a2 , a3 , a4);b = (b1 , b2 , b3 , b4)。
点积乘法规则:a · b = a1b1 + a2b2 + a3b3 + a4b4
模块化加法器和加法树乘法器

module vector(
	input [3:0] a1,a2,a3,a4,b1,b2,b3,b4,
	output [9:0] out);
	wire [7:0] out1,out2,out3,out4;
	wire c_mid;
	//实例化加法器树乘法器
	mul_addtree u1(.mul_a(a1),.mul_b(b1),.mul_out(out1));
	mul_addtree u2(.mul_a(a2),.mul_b(b2),.mul_out(out2));
	mul_addtree u3(.mul_a(a3),.mul_b(b3),.mul_out(out3));
	mul_addtree u4(.mul_a(a4),.mul_b(b4),.mul_out(out4));
	
	assign out=out1+out2+out3+out4;

endmodule

Wallace树型乘法器

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

module wallace_tree (
    input [3:0] a,b,
    output [7:0] dout
);
    
    wire [15:0] tem_and;
    assign tem_and = {               a[3],a[2],a[1],a[0],
                                a[3],a[2],a[1],a[0],
                           a[3],a[2],a[1],a[0],
                      a[3],a[2],a[1],a[0],} & 
                     {b[0],b[0],b[0],b[0],
                      b[1],b[1],b[1],b[1],
                      b[2],b[2],b[2],b[2],
                      b[3],b[3],b[3],b[3],
                    };
        //第一级产生的sum1_x和cout1_x,2个半加器
    //         * * * * 
    //       * * * * 
    //     * + + *
    //   * * + + 

    wire sum1_1,sum1_2;
    wire cout1_1,cout1_2;
    
    half_adder u1_1(.a(tem_and[10]),.b(tem_and[15]),.sum(sum1_1),.c_out(cout1_1));
    half_adder u1_2(.a(tem_and[9]), .b(tem_and[14]),.sum(sum1_2),.c_out(cout1_2));
    
    //第二级产生的sum2_x和cout2_x,3个全加器,1个半加器
    //           * * * * 
    //        *  * * * 
    //     *  s1 s2 *
    //   * *  c2 
    //     c1

    wire sum2_1,sum2_2,sum2_3,sum2_4;
    wire cout2_1,cout2_2,cout2_3,cout2_4;

    full_adder u2_1(.a(tem_and[8]),.b(tem_and[13]),.c(cout1_1),    .sum(sum2_1),.c_out(cout2_1));
    full_adder u2_2(.a(tem_and[5]),.b(sum1_1),     .c(cout1_2),    .sum(sum2_2),.c_out(cout2_2));
    full_adder u2_3(.a(tem_and[0]),.b(tem_and[5]), .c(sum1_2),     .sum(sum2_3),.c_out(cout2_3));
    half_adder u2_4(.a(tem_and[6]),.b(tem_and[11]),.sum(sum2_4),   .c_out(cout2_4));

    //第三级可使用超前进位加法器,这里直接相加
    //            s3  * * * 
    //         s2 c4 s4 * 
    //      s1 c3 
    //   *  c2 
    //   c1  
    wire [6:0] tem_fast_add;
    assign tem_fast_add = {tem_and[12],sum2_1, sum2_2, sum2_3, tem_and[1],tem_and[2]} + {
                           cout2_1,    cout2_2,cout2_3,cout2_4,sum2_4,    tem_and[7]};

    assign dout={tem_fast_add,tem[3]};

endmodule

//全加器
module full_adder(
	input a,b,c,
	output sum,c_out);
	assign {c_out,sum} = a+b+c;
endmodule

//半加器
module half_adder(
	input a,b,
	output c_out,sum);
	assign c_out = a&b;
	assign sum = a|b;
endmodule

复数乘法器

在这里插入图片描述
在这里插入图片描述
//调用Wallace树乘法器

module complex(
	input [3:0] a,b,c,d;
	output [8:0] out_real,out_im);
	wire [7:0] ad,ac,bc,bd;
	wallace u1(.x(a),.y(d),.out(ad);
	wallace u2(.x(a),.y(c),.out(ac);
	wallace u3(.x(d),.y(b),.out(bd);
	wallace u4(.x(b),.y(c),.out(bc);
	assign out_real = ac - bd;
	assign out_im 	= ad + bc;
endmodule

Booth乘法器

在这里插入图片描述

module dut (
    input [7:0] a,
    input [7:0] b,
    output [15:0] out_mul
);
    //暂存y5+y6-2*y7
    //y3+y4-2*y5
    //y1+y2-2*y3
    //y-1+y0-2*y1计算相减会引入补码,增大复杂度
    
    //8位的Booth2位乘:Y=(y5+y6-2*y7)*(2**6) + (y3+y4-2*y5)*(2**4) + (y1+y2-2*y3)*(2**2) + (y-1+y0-2*y1)*(2**0)
    
    //直接判断相减的  所有  结果:
    //000——0,001——-2,010——1,011——-1
    //100——1,101——-1,110——2,111——0
    //  {a[5],a[6],a[7]}==3'b000 ?

    //变成补码,则此时默认a,b以原码的形式
    wire [7:0] a_com,b_com;
    //assign a_com = (a[7])? {a[7],(~a[6:0]+1'b1)} : a;
    //assign b_com = (b[7])? {b[7],(~b[6:0]+1'b1)} : b;
    assign a_com = a, b_com = b;//计算机以补码的形式存储数据

    //8位数的Booth二位乘分别暂存于下列值(左移0,2,4,6位)
    reg [15:0] tem_0,tem_2,tem_4, tem_6;
    reg [15:0] mid_0,mid_2,mid_4,mid_6;//存储中间值,若为负,取其补码

    //always @(*) begin里面是reg!!!!!!!!!!!!!!!!

    //*(2**6)
    always @(*) begin
        case ( {a[5],a[6],a[7]} )
            3'b000,3'b111 : //0
            begin
            tem_6='b0; 
            end
            
            3'b010,3'b100 : //1
            begin
            tem_6= {{2{b[7]}},b_com,6'b0};
            end
            
            3'b101,3'b011 : //-1
            begin
            mid_6= {{2{b[7]}},b_com,6'b0};
            tem_6 =~mid_6+1;
            end
            
            3'b110        : //2
            begin
            tem_6= {b[7],b_com,7'b0}; 
            end
            
            3'b001        : //-2
            begin
            mid_6 = {b[7],b_com,7'b0};
            tem_6= ~mid_6 + 1; 
            end
        endcase    
    end

    //*(2**4)
    always @(*) begin
        case ( {a[3],a[4],a[5]} )
            3'b000,3'b111 : //0
            begin
            tem_4 ='b0; 
            end
            
            3'b010,3'b100 : //1
            begin
            tem_4 = {{4{b[7]}},b_com,4'b0};
            end
            
            3'b101,3'b011 : //-1
            begin
            mid_4 = {{4{b[7]}},b_com,4'b0};
            tem_4 = ~mid_4 + 1;
            end
            
            3'b110        : //2
            begin
            tem_4 = {{3{b[7]}},b_com,5'b0}; 
            end
            
            3'b001        : //-2
            begin
            mid_4 =  {{3{b[7]}},b_com,5'b0}; 
            tem_4 = ~mid_4 + 1; 
            end
        endcase    
    end

    //*(2**2)
    always @(*) begin
        case ( {a[1],a[2],a[3]} )
            3'b000,3'b111 : //0
            begin
            tem_2='b0; 
            end
            
            3'b010,3'b100 : //1
            begin
            tem_2= {{6{b[7]}},b_com,2'b0};
            end
            
            3'b101,3'b011 : //-1
            begin
            mid_2 = {{6{b[7]}},b_com,2'b0};
            tem_2= ~mid_2 + 1;
            end
            
            3'b110        : //2
            begin
            tem_2= {{5{b[7]}},b_com,3'b0}; 
            end
            
            3'b001        : //-2
            begin
            mid_2 = {{5{b[7]}},b_com,3'b0}; 
            tem_2 = ~mid_2 + 1; 
            end
        endcase    
    end

    //*(2**0)
    always @(*) begin
        case ( {1'b0,a[0],a[1]} ) //y(x-1)+y(x)-2*y(x+1)
            3'b000,3'b111 : //0
            begin
            tem_0='b0; 
            end
            
            3'b010,3'b100 : //1
            begin
            tem_0= {{8{b[7]}},b_com}; 
            end
            
            3'b101,3'b011 : //-1
            begin
            mid_0 = {{8{b[7]}},b_com};
            tem_0 = ~mid_0 + 1;
            end
            
            3'b110        : //2
            begin
            tem_0= {{7{b[7]}},b_com,1'b0};  
            end
            
            3'b001        : //-2
            begin
            mid_0 = {{7{b[7]}},b_com,1'b0}; 
            tem_0 = ~mid_0 + 1;
            end
        endcase    
    end

    assign out_mul = tem_0 + tem_2 + tem_4 + tem_6;//可采用超前进位加法器进一步增速
    
endmodule

在这里插入图片描述

Testbench

`timescale 1ns / 1ns
//
// Company: 
// Engineer: CLL
// 
// Create Date: 2020/03/04 16:42:17
// Design Name: 
// Module Name: dsram_tsb
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//
 
 
module dut_tb(
 
    );   
    reg [7:0]       a   ;
    reg [7:0]       b   ;
    wire [15:0] out_mul  ;
    
    initial begin
        #1
        a = -8'd6;
        b = -8'd7;
        #50
        a = 8'd6;
        b = -8'd7;
        #50
        a = -8'd6;
        b = 8'd7;
        #50
        a = -8'd15;
        b = -8'd10;
        #50
        a = -8'd10;
        b = -8'd10;
        #50
        a = -8'd15;
        b = -8'd200;
        #50
        a = 8'd11;
        b = -8'd11;
        #50
        a = -8'd15;
        b = 8'd10;
        #50
        a = 8'd12;
        b = 8'd12;
    end


    dut inst(
        .a         (a         ),
        .b         (b         ),
        .out_mul  (out_mul  )
    );
endmodule

片内存储器设计

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

单端口RAM

例:用Verilog HDL设计深度为8,位宽为8的单端口RAM(单口RAM,只有一套地址总线,读操作和写操作是分开的)1:读 0:写
当片选信号无效时,输出8’bzzzz_zzzz

module ram_single (
    input clk,
    input [2:0] addm,   //address signal
    input cs_n,         //chip select signal
    input we_n,         // 0:write 1:read
    input [7:0] din,

    output reg [7:0] dout,//sequential not forget reg
);
    
    reg [7:0] mem1 [7:0];

    always @(posedge clk)
    begin
        if ( we_n & cs_n)
            dout <= mem1[addm];
        else if (!we_n & cs_n)
            mem1 [addm] <= din;
        else
            dout <= 8'bzzzz_zzzz;
    end
endmodule

双端口RAM

例:用Verilog HDL设计深度为8,位宽为8的双端口RAM。
双口RAM具有两套地址总线,一套用于读数据,另一套用于写数据。二者可以分别独立操作。

module ram_dual (
    input clk1,
    input [2:0] add_in,   //address signal
    input [7:0] din,
    input write,         // 0:write 1:read

    input clk2,
    input read,         //chip select signal
    input [2:0] add_out,
    output reg [7:0] dout,//sequential not forget reg
);
    
    reg [7:0] mem1 [7:0];

    always @(posedge clk1)
    begin
        if ( write )
            mem1 [add_in] <= din;
        else
            mem1 [add_in] <= mem1 [add_in];
    end

    always @(posedge clk2 )
    begin
        if ( read )
            dout <= mem1 [add_out];
        else
            dout <= mem1 [add_out]; 
    end

endmodule

ROM

(2)ROM的Verilog HDL描述
ROM即只读存储器,是一种只能读出事先存储的数据的存储器,其特性是存入数据无法改变,也就是说这种存储器只能读不能写。由于ROM在断电之后数据不会丢失,所以通常用在不需经常变更资料的电子或电脑系统中,资料并不会因为电源关闭而消失。
采用initial初始化ROM中的值,并不修改

module rom (
    input clk,cs_n,
    input [2:0] addm,
    output reg [7:0] dout,
);
    reg [7:0] rom [7:0];//定义一个rom

    //数据存储为固定值
    initial 
    begin
        rom[0] = 8'b0000_0000;
        rom[1] = 8'b0000_0010;
        rom[3] = 8'b0000_0011;
        rom[4] = 8'b0000_0100;

        rom[5] = 8'b0000_0101;
        rom[6] = 8'b0000_0110;
        rom[7] = 8'b0000_0111;
        rom[8] = 8'b0000_1000;
    end

    always @(posedge clk) 
    begin
        if ( !cs_n ) 
            dout <= rom[addm];
        else
            dout <= 8'bzzzz_zzzz; 
    end

endmodule

同步FIFO

FIFO (First In First Out)是一种先进先出的数据缓存器,通常用于接口电路
的数据缓存。与普通存储器的区别是没有外部读写地址线,可以使用两个时
钟分别进行写和读操作。FIFO只能顺序写入数据和顺序读出数据,其数据地
址由内部读写指针自动加1完成,不能像普通存储器那样可以由地址线决定读
取或写入某个指定的地址。

FIFO由存储器块和对数据进出FIFO的通道进行管理的控制器构成,每次只对
一个寄存器提供存取操作,而不是对整个寄存器阵列进行。FIFO有两个地址
指针,一个用于将数据写入下一个可用的存储单元,一个用于读取下一个未
读存储单元的操作。读写数据必须一次进行。

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

在这里插入图片描述
同步FIFO就是读写时钟域均为同一个时钟的FIFO。
clk:读写时钟
rst_n:同步复位信号
wr_en:写使能信号
rd_en:读使能信号
din:输入数据信号
dout:读出数据信号
full:满信号
empty:空信号

整体模块包含:写模块,读模块,更新指针,FIFO计数模块

`timescale 1ns / 1ns
//
// Company: 
// Engineer: 
// 
// Create Date: 2022/02/24 18:47:02
// Design Name: 
// Module Name: inst
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module inst 
    #(parameter		DATA_SIZE = 8,
	 parameter		ADDR_SIZE = 8
	 )(
    input  clk,                     //
    input  rst_n,                   //同步复位
    input  wr_en,                   //写使能、读使能
    input  rd_en,                   
    input  [DATA_SIZE-1:0] din,     //输入输出数据

    output reg [DATA_SIZE-1:0] dout,    
    output  full,                    //输出空满状态
    output  empty);


    
    reg [DATA_SIZE-1:0] mem1 [0:ADDR_SIZE-1]; //reg [wordsize : 0] array_name [0 : arraysize];

    //定义读写指针
    reg [2:0] wr_ptr;
    reg [2:0] re_ptr;

    //定义计数器,记录存入数据个数
    reg [3:0] fifo_ctr;

    assign full  = (fifo_ctr==4'b1000)?1'b1:1'b0;
    assign empty = (fifo_ctr==4'b0)?  1'b1:1'b0;

    //读操作read
    always @( posedge clk ) begin
        if (!empty&rd_en) //读有效,FIFO非空
            dout <= mem1[re_ptr];
        else if (empty & rd_en & wr_en) //空,但读写同时有效
            dout <= din;
        else
            dout <= 'b0;
    end

    //写操作write
    always @( posedge clk ) begin
        if (!full & wr_en)
            mem1[wr_ptr] <= din;
        else if (wr_en & rd_en) 
            //读写同时有效,先进先出,数据总数不变,相当于数据出去并补足一位
            mem1[wr_ptr] <= din;    
    end

    //清空FIFO,FIFO复位之后empty信号默认为高,
    //在工作中需要一次性清空FIFO中的数据时,
    //要对FIFO的复位信号产生一个上升沿即可实现FIFO的清空

    //指针生成pointer
    always @( posedge clk ) begin
        if (!rst_n) begin
            re_ptr <= 3'b0; //从低地址开始读
            wr_ptr <= 3'b0; //从低地址开始读
            end
        else begin
            //注意读写同时有效的情况,指针发生改变,但是数据总量不变
            re_ptr <= ((!empty & rd_en) || (wr_en & rd_en))? re_ptr+3'b1 : re_ptr;
            wr_ptr <= ((!full  & wr_en) || (wr_en & rd_en))? wr_ptr+3'b1 : wr_ptr;
            //写指针满后自动指向[0]
            end
    end

    //计数器counter
    always @( posedge clk ) begin
        if (!rst_n)
            fifo_ctr <= 'b0;
        else begin
        case ({rd_en , wr_en})
            2'b00: fifo_ctr <= fifo_ctr;
            2'b01: fifo_ctr <= (!full) ?  fifo_ctr+1 : fifo_ctr;
            2'b10: fifo_ctr <= (!empty)?  fifo_ctr-1 : fifo_ctr;
            2'b11: fifo_ctr <= fifo_ctr;
            default: fifo_ctr <= fifo_ctr;
        endcase
        end
    end

endmodule


Testbench
来源于

`timescale 1ns / 1ps

module TB_async_fifo;

    parameter		DATA_SIZE = 8;
    parameter		ADDR_SIZE = 8;
    parameter		CLK_PERIOD = 10;
    integer			i 		  = 3;
    
    reg		clk;
    reg		rst_n;
    reg		w_en;
    reg		r_en;
    reg		[DATA_SIZE-1:0] wdata;
    
    wire	[DATA_SIZE-1:0] rdata;
    wire	wfull;
    wire	rempty;
    
    initial begin
    	clk = 0;
    end
    always#(CLK_PERIOD/2) clk = ~clk;
    
    initial begin;
    	rst_n = 1'b0;
    	#15;
    	rst_n = 1'b1;
    end

//	always@(rst_n or wfull) begin
//		if(rst_n==1'b0)
//			w_en = 1'b0;
//		else if(!wfull) 
//			w_en = 1'b1;
//		else
//			w_en = 1'b0;	
//	end

	always@(posedge clk or negedge rst_n) begin
		if(rst_n==1'b0)
			w_en = 1'b0;
		else if(!wfull) 
			w_en = 1'b1;
		else
			w_en = 1'b0;	
	end
	
	always@(rst_n or rempty) begin
		if(rst_n==1'b0)
			r_en =1'b0;
		else if(!rempty)
			r_en = 1'b0;
		else
			r_en = 1'b0;
	end
	
//always@(posedge clk or negedge rst_n) begin
//	if(rst_n==1'b0)
//		r_en =1'b0;
//	else if(!rempty)
//		r_en = 1'b1;
//	else
//		r_en = 1'b0;
//end

	always@(posedge clk or negedge rst_n) begin
		if(rst_n==1'b0)
			i <= 3;
		else if(!wfull)
			i <= i+1;
		else
			i <= i;
	end 
	
	always@(*) begin
		if(rst_n==1'b0) 
			wdata = 0;
		else if(!wfull&&w_en==1)
			wdata = i;
		else
			wdata <= 0;
	end   
    
    
    
		inst#(
    	.DATA_SIZE(DATA_SIZE),
    	.ADDR_SIZE(ADDR_SIZE)
    	)
    	uut(
    	.clk(clk),
    	.rst_n(rst_n),
    	.wr_en(w_en),
    	.rd_en(r_en),
    	.din(wdata),
    	.dout(rdata),
    	.full(wfull),
    	.empty(rempty)
        );
endmodule


参考

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

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值