Verilog代码练习小案例(持续更新)

1.呼吸灯设计

  1. 要求:完成呼吸灯设计,要求从亮到灭时间为2s,从灭到亮时间也为2s,完成一个完整的呼吸需要4s。
  2. 分析:需要产生一个逐渐改变占空比的方波,即PWM(脉冲宽度调制)。具体方案为:将2s平均分成1000份(即每份时长为2ms),第一份占空比为1000/1000,第二份占空比为999/1000,以此类推。能实现从亮到灭的过程,而从灭到亮则是其反过程。

1.1波形设计:

在这里插入图片描述

1.2代码设计与tb

1.2.1 代码

module breath_led(
	input wire clk,
	input wire rst,
	output reg led
);
reg[9:0]pwm_cyc_cnt,cnt50m_1000;
reg[6:0]cnt50m;
reg flag;

parameter cnt50m_end=99;
parameter cnt50m_1000_end=999;
parameter pwm_cyc_cnt_end=999;

//cnt50m
always @(posedge clk) begin 
	if(rst==1'b1) begin
		cnt50m<='d0;
	end 
	else if (cnt50m==cnt50m_end) begin
		cnt50m<='d0;
	end
	else
		cnt50m<=cnt50m+1'b1;
end

//cnt50m_1000
always @(posedge clk) begin 
	if(rst==1'b1) begin
		cnt50m_1000 <='d0;
	end 
	else if (cnt50m==cnt50m_end&&cnt50m_1000==cnt50m_1000_end) begin
		cnt50m_1000<='d0;
	end
	else if (cnt50m==cnt50m_end) begin
		cnt50m_1000<=cnt50m_1000+1'b1;
	end
		
end
// pwm_cyc_cnt
always @(posedge clk) begin 
	if(rst==1'b1) begin
		pwm_cyc_cnt <= 'd0;
	end 
	else if (cnt50m==cnt50m_end && cnt50m_1000==cnt50m_1000_end && pwm_cyc_cnt==pwm_cyc_cnt_end) begin
		pwm_cyc_cnt <= 'd0;
	end
	else if (cnt50m==cnt50m_end&&cnt50m_1000==cnt50m_1000_end) begin
		pwm_cyc_cnt <= pwm_cyc_cnt+1'b1;
	end
end

//led_flag
always @(posedge clk) begin 
	if(rst==1'b1) begin
		flag <= 'd0;
	end 
	else if (cnt50m==cnt50m_end && cnt50m_1000==cnt50m_1000_end && pwm_cyc_cnt==pwm_cyc_cnt_end) begin
		flag=~flag;
	end
end

always @(posedge clk) begin 
	if(rst==1'b1) begin
		led <='d0;
	end 
	else if (flag==1'b0) begin
		if (cnt50m_1000<pwm_cyc_cnt) begin
			led<='d0;
		end
		else
			led<='d1;
	end
	else if (flag==1'b1) begin
		if (cnt50m_1000<pwm_cyc_cnt) begin
			led<='d1;
		end
		else
			led<='d0;
	end
end
endmodule 


1.2.2 tb

module tb_breath_led();
reg clk;
reg rst;
wire led;

initial begin
    clk=0;
    rst=1;
    #100
    rst=0;
end

always #10 clk=~clk;  

breath_led inst_breath_led (
			.clk (clk),
			.rst (rst),
			.led (led)
		);

endmodule

1.3仿真

在这里插入图片描述

2.计数器实现奇数分频

  1. 要求:假设原时钟sclk周期为10ns,现要在sclk的基础上实现五分频时钟clk5
  2. 分析:clk5的周期为50ns,默认占空比为50%,则高电平持续25ns,低电平持续25ns。

2.1 波形设计:

在这里插入图片描述
这里主要注意一下关键部分:分别用时钟的上升沿和下降沿去采样,这样就能得到奇数倍的分频,代码部分比较简单,这里省略。

3.完成一个top_down设计

  1. 要求:实现pi_a、pi_b在4个clk周期内相与一次。
  2. 分析:这里涉及两个功能:分频和相与,因此可以将其划分成两个功能模块去实现。

模块框图:
在这里插入图片描述

在这里插入图片描述

3.1 波形设计:

在这里插入图片描述

3.2 代码与tb:

分频设计:

module div_clk (
	input wire clk,
	input wire rst,
	output reg po_flag
);

reg[1:0] cnt;

always @(posedge clk) begin 
	if(rst==1'b1) begin
		cnt <= 'd0;
	end
	else
		cnt<=cnt+1'b1;
end

always @(posedge clk) begin 
	if(rst==1'b1) begin
		 po_flag<='d0;
	end 
	else if (cnt=='d2) begin
		po_flag<='d1;
	end
	else if (cnt=='d3) begin
		po_flag<='d0;
	end
end

endmodule 


相与:

module a_and_b (
	input wire clk,    // Clock
	input wire rst,
	input wire pi_flag,
	input wire pi_a,
	input wire pi_b,
	output reg po_c
	
);

always @(posedge clk) begin 
	if(rst==1'b1) begin
		po_c <='d0;
	end 
	else if (pi_flag==1'b1) begin
		po_c<=pi_a & pi_b;
	end 
	else
		po_c<='d0;
end

endmodule 

顶层设计

module top(
	input wire clk,    // Clock
	input wire rst,
	input wire pi_a,
	input wire pi_b,
	output wire po_c
	);
wire po_flag;

div_clk inst_div_clk 
(.clk(clk),
 .rst(rst),
 .po_flag(po_flag));

a_and_b inst_a_and_b 
(.clk(clk),
 .rst(rst),
 .pi_flag(po_flag),
 .pi_a(pi_a),
 .pi_b(pi_b),
 .po_c(po_c));

endmodule

tb

module tb_top();
reg clk;
reg rst;
reg pi_a;
reg pi_b;
wire po_c;

initial begin
	clk=0;
	rst=1;
	#100
	rst=0;
end

always #5 clk=~clk;
always #10 pi_a={$random};
always #10 pi_b={$random};


top inst_top 
(.clk(clk),
 .rst(rst),
 .pi_a(pi_a),
 .pi_b(pi_b),
 .po_c(po_c));

endmodule

3.3 仿真

在这里插入图片描述

4.完成一个top_down设计(在3的基础上实现)

4.1 波形设计

在这里插入图片描述

4.2 代码与tb(这里主要是在四分频的基础上又进行了一次四分频,代码变动不大,故省略)

5.自动售货机(简易版)

  1. 要求:假设可乐3元一瓶,每次投币只能投入1元。完成设计和仿真
  2. 分析:涉及状态转换类的,一般需要有限状态机设计,需要画出状态转换图。

5.1 状态转换图

在这里插入图片描述
模块信号示意图:
在这里插入图片描述

5.2代码设计与tb

5.2.1 代码

module fsm(
    input wire clk,
    input wire rst,
    input wire pi_money,
    output reg po_cola
    );

parameter IDLE=3'b001;
parameter  ONE=3'b010;
parameter  TWO=3'b100;

reg [2:0] state;

always @(posedge clk) begin 
    if(rst==1'b1) begin
         state<=IDLE;
    end
    else case (state) 
             IDLE:begin
                if (pi_money==1'b1) begin
                    state<=ONE;
                end
                else
                    state<=IDLE;
             end

             ONE:begin
                if (pi_money==1'b1) begin
                    state<=TWO;
                end
                else 
                    state<=ONE;
             end

             TWO:begin
                if (pi_money==1'b1) begin
                    state<=IDLE;
                end
                else
                    state<=TWO;
             end                  
             default : state<=IDLE;
         endcase
    end

always @(posedge clk) begin 
    if(rst==1'b1) begin
        po_cola <= 'd0;
    end 
    else if (state==TWO && pi_money==1'b1) begin
        po_cola<=1'b1;
    end
    else
        po_cola<='d0;
end


endmodule

5.2.2 tb

module tb_sim();
	reg clk;
	reg rst;
	reg pi_money;
	wire po_cola;

initial begin
	clk=0;
	rst=1;
	#30
	rst=0;
end

always #5 clk=~clk;
always #10 pi_money={$random};

	fsm  inst_fsm (
			.clk      (clk),
			.rst      (rst),
			.pi_money (pi_money),
			.po_cola  (po_cola)
		);

endmodule

5.3仿真

在这里插入图片描述

6.自动售货机(复杂版)

6.1状态转换图

在这里插入图片描述
模块信号示意图
在这里插入图片描述

6.2代码设计与tb

6.2.1代码

module fsm (
    input wire clk,    // Clock
    input wire rst, 
    input wire pi_money,  // high:1, low:0.5元
    output reg po_cola,
    output reg po_money
);

parameter IDLE=5'b00001;
parameter HALF=5'b00010;
parameter ONE=5'b00100;
parameter ONE_HALF=5'b01000;
parameter TWO=5'b10000;

reg [4:0] state;

always @(posedge clk) begin 
    if(rst==1'b1) begin
        state <= IDLE;
    end 
    else case (state)
    IDLE:begin
        if(pi_money==1'b1)
            state<=ONE;
        else
            state<=HALF;
    end
    HALF:begin
        if (pi_money==1'b1) begin
            state<=ONE_HALF;
        end
        else 
            state<=ONE;
    end
    ONE:begin
        if (pi_money==1'b1) begin
            state<=TWO;
        end
        else 
            state<=ONE_HALF;
    end
    ONE_HALF:begin
        if (pi_money==1'b1) begin
            state<=IDLE;
        end
        else 
            state<=TWO;
    end
    TWO:begin
        state<=IDLE;
    end   
        default : state<=IDLE;
    endcase
end

always @(posedge clk) begin 
    if(rst==1'b1) begin
        po_cola <= 'd0;
    end 
    else if (state==ONE_HALF && pi_money==1'b1) begin
        po_cola<=1'b1;
    end 
    else if (state==TWO) begin
        po_cola<=1'b1;
    end
    else
        po_cola<='d0;
end

always @(posedge clk) begin
    if(rst==1'b1) begin
        po_money <='d0;
    end 
    else if (state==TWO && pi_money==1'b1) begin
        po_money<='d1;
    end
    else 
        po_money<='d0;
end


endmodule 

6.2.2tb

module tb_sim();
	reg clk;
	reg rst;
	reg pi_money;

	wire po_cola;
	wire po_money;

initial begin
	clk=0;
	rst=1;
	#30
	rst=0;
end

always #5 clk=~clk;
always #10 pi_money={$random}; 

	fsm inst_fsm (
			.clk      (clk),
			.rst      (rst),
			.pi_money (pi_money),
			.po_cola  (po_cola),
			.po_money (po_money)
		);

endmodule

6.3 仿真

在这里插入图片描述

7.按键消抖设计

按键模型:
在这里插入图片描述
理想按键波形:
在这里插入图片描述
实际按键波形:
在这里插入图片描述
按键消抖设计思想:
由于clk是ns级别,而按键一般是ms级别,因此clk会采集到非常多次key,如果不进行按键消抖,则会被认为按下了很多次按键。从实际按键波形图可以看到,按下一次按键key后会经历:前抖动→较长时间的低电平→后抖动,因此我们可以给出这样的设计方式:
当key低电平持续时间为5~10ms的时候,可以给出一个标志,此标志意味着一次按键按下。

7.1 按键消抖波形设计

在这里插入图片描述

7.2代码与tb

7.2.1代码

module key_debounce(
    input wire clk,
    input wire rst,
    input wire key,
    output reg po_key_flag
    );

reg [17:0]cnt;
reg cnt_flag;

parameter cnt_mux=250000-1;

always @(posedge clk) begin 
    if(rst==1'b1) begin
        cnt <= 'd0;
    end 
    else if (key==1'b0) begin
        cnt<=cnt+1'b1;
    end
    else 
        cnt<='d0;
end

always @(posedge clk) begin 
    if(rst==1'b1) begin
        cnt_flag <= 'd0;
    end 
    else if (cnt==cnt_mux) begin
        cnt_flag<='d1;
    end
    else if (cnt_flag==1'b1 && key==1'b1) begin
        cnt_flag<='d0;
    end
end

always @(posedge clk) begin 
    if(rst==1'b1) begin
        po_key_flag <= 'd0;
    end 
    else if (cnt==cnt_mux && cnt_flag==1'b0) begin
       po_key_flag<='d1;
    end
    else
        po_key_flag<='d0;
end
endmodule

7.2.2 tb

module tb_key_debounce();

parameter CLK_PERIOD=20;

	reg clk;
	reg rst;
	reg key;
	wire po_key_flag;

	key_debounce inst_key_debounce 
	(.clk(clk),
	 .rst(rst),
	 .key(key),
	 .po_key_flag(po_key_flag)
	   );


		initial begin
			clk=0;
			rst=1;
			#30
			rst=0;
		end

		always #((CLK_PERIOD/2)) clk=~clk;

	    initial begin
	    //前抖
        key = 0;
        #200;
        key = 1;  

        #200;
        key = 0;
        #500;
        key = 1;

        #200;
        key = 0;
        #1000; //1ms
        key = 1;

        //按键持续
        #200;
        key = 0;
        #13000; //13ms
        key = 1;

		//后抖
        #200
        key=0;
        #200
        key=1;
        #200
        key=0;
      
    end

endmodule

7.3仿真

在这里插入图片描述

8 按键控制自动售货机设置

要求:
在这里插入图片描述

分析,这里共涉及这几个模块:
1.fsm模块负责实现自动售货机的状态跳转。
2.两个流水灯模块:led_water_sigle 和led_water_double。
3.按键消抖模块
4.顶层top模块

8.1 系统构架框图

在这里插入图片描述

8.2状态转换图

在这里插入图片描述

8.3 波形图

8.3.1 状态机模块波形:

在这里插入图片描述

8.3.2 Led_water_sigle波形:

在这里插入图片描述

8.3.3 Led_water_double波形:

在这里插入图片描述

8.4 代码部分

8.4.1 fsm

module fsm (
    input wire clk,    // Clock
    input wire rst, 
    input wire key_1,  //5毛
    input wire key_2,  //1元
    input wire [3:0]led1,
    input wire [3:0]led2,
    output reg [3:0]led
);

parameter IDLE=7'b0000001;
parameter HALF=7'b0000010;
parameter  ONE=7'b0000100;
parameter ONE_HALF=7'b0001000;
parameter TWO=7'b0010000;
parameter LED1=7'b0100000;
parameter LED2=7'b1000000;

parameter END_10S = 500000000-1;

reg[6:0]state;
reg[28:0] cnt_10;

always @(posedge clk) begin 
    if(rst==1'b1) begin
        state <= IDLE;
    end 
    else case (state)
    IDLE:begin
        if (key_1==1'b1) begin
            state<=HALF;
        end
        else if (key_2==1'b1) begin
            state<=ONE;
        end
    end
    HALF:begin
        if (key_1==1'b1) begin
            state<=ONE;
        end
        else if (key_2==1'b1) begin
            state<=ONE_HALF;
        end      
    end
    ONE:begin
        if (key_1==1'b1) begin
            state<=ONE_HALF;
        end
        else if (key_2==1'b1) begin
            state<=TWO;
        end
    end
    ONE_HALF:begin
        if (key_1==1'b1) begin
            state<=TWO;
        end
        else if (key_2==1'b1) begin
            state<=LED1;
        end
    end
    TWO:begin
        if (key_1==1'b1) begin
            state<=LED1;
        end
        else if (key_2==1'b1) begin
            state<=LED2;
        end
    end
    LED1:begin
        if (cnt_10==END_10S) begin
            state<=IDLE;
        end     
    end 
    LED2:begin
        if (cnt_10==END_10S) begin
            state<=IDLE;
        end
    end
        default : state<=IDLE;
    endcase
end

//cnt_10
always @(posedge clk) begin 
    if(rst==1'b1) begin
        cnt_10 <= 'd0;
    end 
    else if (cnt_10==END_10S) begin
        cnt_10<='d0;
    end
    else if (state==LED1 || state==LED2) begin
        cnt_10<=cnt_10+1'b1;
    end
end

// led
always @(posedge clk) begin 
    if(rst==1'b1) begin
         led<= 4'b0000;
    end
    else case (state)
        IDLE:led<=4'b0000;
        HALF:led<=4'b0001;
         ONE:led<=4'b0010;
    ONE_HALF:led<=4'b0100;
         TWO:led<=4'b1000; 
         LED1:led<=led1;
         LED2:led<=led2;  
        default :led<=4'b0000;
    endcase
end


endmodule 

8.4.2 led_water_sigle

module led_water_sigle(
	input wire clk,
	input wire rst,
	output reg [3:0] led
    );
parameter CNT_END=12500000-1;
reg[23:0]cnt;
reg shift_flag;
//cnt
always @(posedge clk) begin 
	if(rst==1'b1) begin
		cnt <= 'd0;
	end 
	else if (cnt==CNT_END) begin
		cnt<='d0;
	end
	else 
		cnt<=cnt+1'b1;
end

// shift_flag
always @(posedge clk) begin 
	if(rst==1'b1) begin
		shift_flag <= 'd0;
	end 
	else if (cnt==CNT_END) begin
		shift_flag<='d1;
	end
	else
		shift_flag<='d0;
end

//led
always @(posedge clk) begin 
	if(rst==1'b1) begin
		 led<= 4'b0001;
	end 
	else if (shift_flag==1'b1) begin
		led<={led[2:0],led[3]};
	end
end
endmodule

8.4.3 led_water_double

module led_water_double(
	input wire clk,
	input wire rst,
	output reg [3:0] led

    );
parameter CNT_END=12500000-1;
reg[23:0]cnt;
reg shift_flag;
reg L_shift_flag;
//cnt
always @(posedge clk) begin 
	if(rst==1'b1) begin
		cnt <= 'd0;
	end 
	else if (cnt==CNT_END) begin
		cnt<='d0;
	end
	else 
		cnt<=cnt+1'b1;
end

// shift_flag
always @(posedge clk) begin 
	if(rst==1'b1) begin
		shift_flag <= 'd0;
	end 
	else if (cnt==CNT_END) begin
		shift_flag<='d1;
	end
	else
		shift_flag<='d0;
end

// L_shift_flag
always @(posedge clk) begin 
	if(rst==1'b1) begin
		L_shift_flag <='d0;
	end 
	else if (led==4'b0001) begin
		L_shift_flag<='d1;
	end
	else if (led==4'b1000) begin
		L_shift_flag<='d0;
	end
end

//led
always @(posedge clk) begin 
	if(rst=='d1) begin
		 led<= 4'b0001;
	end 
	else if (L_shift_flag==1'b1 && shift_flag==1'b1) begin
		led<={led[2:0],led[3]};
	end
	else if (L_shift_flag==1'b0 && shift_flag==1'b1) begin
		led<={led[0],led[3:1]};
	end
end


endmodule

8.4.4 key_debounce

module key_debounce(
    input wire clk,
    input wire rst,
    input wire key,
    output reg po_key_flag
    );

reg [17:0]cnt;
reg cnt_flag;

parameter cnt_mux=250000-1;

always @(posedge clk) begin 
    if(rst==1'b1) begin
        cnt <= 'd0;
    end 
    else if (key==1'b0) begin
        cnt<=cnt+1'b1;
    end
    else 
        cnt<='d0;
end

always @(posedge clk) begin 
    if(rst==1'b1) begin
        cnt_flag <= 'd0;
    end 
    else if (cnt==cnt_mux) begin
        cnt_flag<='d1;
    end
    else if (cnt_flag==1'b1 && key==1'b1) begin
        cnt_flag<='d0;
    end
end

always @(posedge clk) begin 
    if(rst==1'b1) begin
        po_key_flag <= 'd0;
    end 
    else if (cnt==cnt_mux && cnt_flag==1'b0) begin
       po_key_flag<='d1;
    end
    else
        po_key_flag<='d0;
end
endmodule

8.4.5 top_key_ctrl_fsm

module top_key_ctrl_fsm(
	input wire clk,
	input wire rst,
	input wire key1,
	input wire key2,
	output wire[3:0] led
    );
wire key_flag1;
wire key_flag2;
wire [3:0]led1;
wire [3:0]led2;

	fsm inst_fsm (
			.clk   (clk),
			.rst   (rst),
			.key_1 (key_1),
			.key_2 (key_2),
			.led1  (led1),
			.led2  (led2),
			.led   (led)
		);


	led_water_sigle inst_led_water_sigle (
		.clk(clk),
		.rst(rst), 
		.led(led1));

	led_water_double inst_led_water_double (
		.clk(clk),
		.rst(rst),
		.led(led2));

	key_debounce inst_key1_debounce
	(.clk(clk), 
	 .rst(rst),
	 .key(key1), 
	 .po_key_flag(key_flag1));

	key_debounce inst_key2_debounce
	(.clk(clk), 
	 .rst(rst),
	 .key(key2), 
	 .po_key_flag(key_flag2));


endmodule

9.对ram进行基础的读写操作

  1. 要求:写出对 ram 控制的 Verilog HDL 代码,要求对该 ram 进行整体的读写交替进行(乒乓操作),要求实现的波形效果如下。
    在这里插入图片描述
  2. 分析:可以看到rd_data和rd_addr之间存在一拍延时,因此在ip核参数选择时需要注意。
  3. ip参数设置如下:
    在这里插入图片描述

9.1代码与tb

9.1.1 ctrl_ram

module ctrl_ram(
    input wire clk,
    input wire rst,
    input wire [7:0] wr_data,
    output wire [7:0] rd_data
    );

reg wr_en;
reg [7:0] wr_addr;
reg [7:0] rd_addr;

// wr_en
always @(posedge clk) begin 
    if(rst==1'b1) begin
       wr_en  <= 'd1;
    end
    else if (wr_addr=='d255) begin
        wr_en<='d0;
    end
    else if (rd_addr=='d255) begin
       wr_en<='d1;
    end
end

//wr_addr
always @(posedge clk) begin 
    if(rst==1'b1) begin
        wr_addr <= 'd0;
    end 
    else if (wr_en==1'b1) begin
        wr_addr<=wr_addr+1'b1;
    end 
    else 
        wr_addr<='d0;
end

//rd_addr
always @(posedge clk) begin 
    if(rst==1'b1) begin
         rd_addr<= 'd0;
    end 
    else if (wr_en=='d0) begin
        rd_addr<=rd_addr+1'b1;
    end
    else
        rd_addr<='d0;
end

ram_r8x256_w8x256 ram_r8x256_w8x256_inst (
  .clka(clk),    // input wire clka
  .wea(wr_en),      // input wire [0 : 0] wea
  .addra(wr_addr),  // input wire [7 : 0] addra
  .dina(wr_data),    // input wire [7 : 0] dina
  .clkb(clk),    // input wire clkb
  .addrb(rd_addr),  // input wire [7 : 0] addrb
  .doutb(rd_data)  // output wire [7 : 0] doutb
);

endmodule

9.1.2 tb

module tb_ctrl_ram();
	reg clk;
	reg rst;
	reg [7:0] wr_data;
	wire [7:0] rd_data;

	initial begin
		clk=0;
		rst=1;
		wr_data='d0;
		#30
		rst=0;
	end

	always #5 clk=~clk;
	always #20 wr_data={$random}%255;

		ctrl_ram inst_ctrl_ram (
			.clk(clk), 
			.rst(rst), 
			.wr_data(wr_data), 
			.rd_data(rd_data));

endmodule

9.2 仿真效果

在这里插入图片描述

10. ram的乒乓操作

  1. 要求:调用两个异步双口 RAM,读写时钟都设置 100Mhz,两个 RAM 为 RAMA 和RAMB,深度为 1024 ,位宽为8bit,写入数据为 8bit@100Mhz 持续数据流,当 RAMA被写入 1024 字节数据后切换到写 RAMB,RAMB 被写入 1024 字节后切换 RAMA以此循环类推。
    当 RAMA 被写入 1024 字节时,给读时序提供一个启动信号读取 RAMA 的数据,读取完 RAMA 的 1024 字节数据时,切换读 RAMB 以此类推。写入 RAMA和B的数据是 0~255 递增的数据。
    两个 RAM 的交替读写操作我们称之为乒乓操作

10.1 波形设计

在这里插入图片描述
ram ip核的参数情况:
在这里插入图片描述

10.2代码与tb

10.2.1 ctrl_ram

module ctrl_ram(
    input wire clk,
    input wire rst,
    input wire [7:0] pi_data,
    output wire [7:0] po_data
    );

reg wr_en_A,wr_en_B;
reg [9:0] wr_addr_A,wr_addr_B;
reg [9:0] rd_addr_A,rd_addr_B;

wire [7:0] po_data_A;
wire [7:0] po_data_B;

assign po_data=(wr_en_A==1'b1)?po_data_B:po_data_A;
//wr_en_A
always @(posedge clk) begin 
    if(rst==1'b1) begin
        wr_en_A <= 'd1;
    end 
    else if (wr_addr_A=='d1023) begin
        wr_en_A<='d0;
    end
    else if (wr_addr_B=='d1023) begin
        wr_en_A<='d1;
    end
end

//wr_en_B
always @(posedge clk) begin 
    if(rst==1'b1) begin
        wr_en_B <= 'd0;
    end 
    else if (wr_addr_A=='d1023) begin
        wr_en_B<='d1;
    end
    else if (wr_addr_B=='d1023) begin
        wr_en_B<='d0;
    end
end

// wr_addr_A
always @(posedge clk) begin 
    if(rst==1'b1) begin
         wr_addr_A<= 'd0;
    end 
    else if (wr_en_A==1'b1) begin
        wr_addr_A<=wr_addr_A+1'b1;
    end 
    else
        wr_addr_A<='d0;

end

// wr_addr_B
always @(posedge clk) begin 
    if(rst==1'b1) begin
        wr_addr_B <= 'd0;
    end 
    else if (wr_en_B=='b1) begin
        wr_addr_B<=wr_addr_B+1'b1;
    end
    else 
        wr_addr_B<='d0;
end

// rd_addr_A
always @(posedge clk) begin 
    if(rst==1'b1) begin
        rd_addr_A <= 'd0;
    end 
    else if (wr_en_A==1'b0) begin
        rd_addr_A<=rd_addr_A+1'b1;
    end
    else
        rd_addr_A<='d0;
end

// rd_addr_B
always @(posedge clk) begin 
    if(rst==1'b1) begin
         rd_addr_B<= 'd0;
    end 
    else if (wr_en_B==1'b0) begin
        rd_addr_B<=rd_addr_B+1'b1;
    end
    else 
        rd_addr_B<='d0;
end


ram_w8x1024_r8x1024 ram_w8x1024_r8x1024_A (
  .clka(clk),    //  // input wire clka
  .wea(wr_en_A),     // input wire [0 : 0] wea
  .addra(wr_addr_A), // input wire [9 : 0] addra
  .dina(pi_data),    // input wire [7 : 0] dina
  .clkb(clk),    //  // input wire clkb
  .addrb(rd_addr_A), // input wire [9 : 0] addrb
  .doutb(po_data_A) // output wire [7 : 0] doutb
);

ram_w8x1024_r8x1024 ram_w8x1024_r8x1024_B (
  .clka(clk),    //  // input wire clka
  .wea(wr_en_B),     // input wire [0 : 0] wea
  .addra(wr_addr_B), // input wire [9 : 0] addra
  .dina(pi_data),    // input wire [7 : 0] dina
  .clkb(clk),    //  // input wire clkb
  .addrb(rd_addr_B), // input wire [9 : 0] addrb
  .doutb(po_data_B) // output wire [7 : 0] doutb
);
endmodule

10.2.2 tb

module tb_ctrl_ram();
	reg clk;
	reg rst;
	reg [7:0] pi_data;
	wire [7:0] po_data;

	initial begin
		clk=0;
		rst=1;
		pi_data='d0;
		#100
		rst=0;
	end

	always #5 clk=~clk;

	initial begin
		#100
		gen_data();
	end

	task gen_data;
		integer i;
		begin
			for ( i = 1; i < 7000; i=i+1) begin
				@(posedge clk);
				pi_data=i[7:0];				
			end
		end
		
	endtask 
	
	ctrl_ram inst_ctrl_ram (
		.clk(clk), 
		.rst(rst), 
		.pi_data(pi_data), 
		.po_data(po_data));


endmodule

10.3 仿真

RAM的交替读写情况:
在这里插入图片描述
ram写细节:
在这里插入图片描述
ram读细节:
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值