【verilog】双口RAM(仿真模型)

模块代码

/*
* 双端口ram,宽度为8,深度为16(所用地址线为4根),
 */

module dpram#(parameter RAM_WIDTH = 8 ,parameter RAM_DEPTH = 16,parameter ADDR_LINE = 4)(
	input wr_clk,
	input rd_clk,
	input wr_en,
	input rd_en,
	input [RAM_WIDTH-1:0]wr_data,
	output reg [RAM_WIDTH-1:0]rd_data,
	input [ADDR_LINE-1:0]wr_addr,
	input[ADDR_LINE-1:0]rd_addr
);
	reg [RAM_WIDTH-1:0] memory[RAM_DEPTH-1:0]; 
	
	//写
	always@(posedge wr_clk)begin
	if(wr_en)
		memory[wr_addr] <= wr_data;
	else
		memory[wr_addr] <= memory[wr_addr];
	end

	//读
	always@(posedge rd_clk)begin
	if(rd_en)
		rd_data <= memory[rd_addr];
	else
		rd_data <= rd_data;
	end

endmodule

//dpram#(.xxx(),.xxx())
//func1(
//	.xxx(),
//	.xxx(),
//	.xxx()
//)

测试代码

`timescale 1ns / 1ps
module tb_dram(); 

reg clk; //cha/chb common clk
reg rst_n;

//写ram端
reg wr_en;  
reg[15:0] wr_data;  
reg[9:0] wr_addr;  
//读ram端
reg rd_en;
wire[15:0] rd_data;  
reg[9:0] rd_addr;  
reg [15:0] data1;
reg [15:0] data2;
reg [15:0] data3;

//state chicken
reg[10:0] cnta_state;
reg[10:0] cntb_state;


//cha:data input chnl
//对ram进行写操作,在选择地址的同时给予数据。
always @ (posedge clk or negedge rst_n)  
begin
    if(!rst_n)begin
    	cnta_state <= 1'b0;
	wr_en <=1'b0;  
	wr_addr <= 10'd0;
	wr_data <= 16'd0;
    end
    else begin
	case(cnta_state)
	0,1,2,3,4,5,6,7,8,9:cnta_state <= cnta_state + 1'b1;
	10:begin wr_en <= 1'b1;wr_addr <= 10'd1;wr_data <= 16'h5555;
	         cnta_state <= cnta_state + 1'b1;
	   end	
	11:begin wr_en <= 1'b1;wr_addr <= 10'd2;wr_data <= 16'haaaa;
	         cnta_state <= cnta_state + 1'b1;
           end
	12:begin wr_en <= 1'b1;wr_addr <= 10'd3;wr_data <= 16'hcccc;
	         cnta_state <= cnta_state + 1'b1;
           end
	default:begin
    		 cnta_state <= 10'd13;
		 wr_en <=1'b0;  
		 wr_addr <= 10'd0;
		 wr_data <= 16'd0;
    	   end
        endcase	
   end
end

//chb:data output chnl
//对ram做读操作,与写操作不同。
//读操作需要等2个clk才能在dout上输出选定地址的有效数据
//配置地址 -> 时序逻辑延迟经过一个clk才成功写入 -> 再过一个clk ->有效数据
always @ (posedge clk or negedge rst_n)  
begin
    if(!rst_n)begin
	rd_en <= 1'b0;
    	cntb_state <= 1'b0;
	data1 <= 1'b0;
	data2 <= 1'b0;
	data3 <= 1'b0;
	rd_addr <= 10'd0;
    end
    else begin
	case(cntb_state)
	0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19:
		 cntb_state <= cntb_state + 1'b1;
	20:begin rd_en <= 1'b1;           //读使能
		 rd_addr <= 10'd1;        //选择地址1
	         cntb_state <= cntb_state + 1'b1;
	   end	
	21:begin  
		  rd_addr <= 10'd2;        //选择地址2
	          cntb_state <= cntb_state + 1'b1;
           end
	22:begin
	          data1 <= rd_data;        //寄存地址1上吐出的数据  
		 rd_addr <= 10'd3;         //选择地址3
	         cntb_state <= cntb_state + 1'b1;
           end
	23:begin
	       	 data2 <= rd_data;         //寄存地址2上吐出的数据	
		 rd_en   <= 1'b0;          //读使能关闭
	         cntb_state <= cntb_state + 1'b1;
           end
	24:begin
                 data3 <= rd_data;         //寄存地址3上吐出的数据
		 rd_addr <= 10'd0;
           end

	default:begin
    		 cntb_state <= 10'd24;
    	   end
        endcase	
   end
end


initial begin clk = 0; rst_n = 0; #50; rst_n = 1'b1; end
initial begin #600; $stop(); end
always # 10 clk = ~clk;

dpram#(.RAM_WIDTH(16),
	      .RAM_DEPTH(1024),
	      .ADDR_LINE(10))
func1(
	.wr_clk(clk),
	.rd_clk(clk),
	.wr_en(wr_en),
	.rd_en(rd_en),
	.wr_addr(wr_addr),
	.rd_addr(rd_addr),
	.wr_data(wr_data),
	.rd_data(rd_data)
);
endmodule


仿真波形

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

搞IC的那些年

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

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

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

打赏作者

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

抵扣说明:

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

余额充值