1. RAM种类区分
单端口RAM:读写数据共用一个地址线,一个时钟沿只能进行读或者写;
伪双端口RAM:写数据和读数据有自己的地址、时钟、读写使能信号;也就是一组端口只能写,一组端口只能读。(读写数据也可共用一个clk,为同步伪双端口ram)
真双端口RAM:一组端口可读可写,另一组端口也可读可写。(若这两组端口共用一个clk,为同步真双端口ram。若每组有每组的clk,为异步真双端口ram)。
三种RAM的接口示意图如下所示:
Figure 单端口RAM连线图
Figure 伪双端口RAM连线图
Figure 真双端口RAM连线图
从上图可以得出:
RAM类型 | 方式 | 数据读写接口 | 地址接口数量 |
---|---|---|---|
单端口RAM | RAM允许通过一个端口对存储进行读写访问 | 1 | 1 |
伪双端口RAM | RAM提供A、B两种接口,A进行写访问,B进行都访问 | 1 | 2 |
真双端口RAM | RAM提供A、B两组接口,A、B都可以进行读写访问 | 2 | 2 |
2. verilog实现
依据上述对各种RAM结构的分析,编写verilog代码有:
2.1 单端口RAM
代码如下:
//sigle_port ram
reg [DATA_WIDTH-1:0] ram_reg[ADDR-1:0];
integer i;
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
for (i=0;i<ADDR;i=i+1)begin
ram_reg[i] <= {DATA_WIDTH{1'b0}};
end
end
else if(wr)begin
ram_reg[addr] <= din[DATA_WIDTH-1:0];
end
end
always @(posedge clk ir negedge rst_n)begin
if(!rst_n)begin
dout <= {DATA_WIDTH{1'b0}};
end
else if(rd)begin
dout <= ram_reg[addr];
end
end
2.2 伪双端口RAM
代码如下:
//simple_dual_port ram
reg [xx-1:0] addr_wr;
reg [xx-1:0] addr_rd;
reg [DATA_WIDTH-1:0] ram_reg[ADDR-1:0];
//here is synchronize clk, not asynchronize clk
integer i;
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
for (i=0;i<ADDR;i=i+1)begin
ram_reg[i] <= {DATA_WIDTH{1'b0}};
end
end
else if(wr)begin
ram_reg[addr_wr] <= din[DATA_WIDTH-1:0];
end
end
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
dout <= {DATA_WIDTH{1'b0}};
end
else if(rd)begin
dout <= ram_reg[addr_rd];
end
end
2.3 真双端口RAM
代码如下:
//real dual_port ram
wire wr_a;
wire wr_b;
reg [xx-1:0] addr_a;
reg [xx-1:0] addr_b;
reg [DATA_WIDTH-1:0] din_a;
reg [DATA_WIDTH-1:0] din_b;
reg [DATA_WIDTH-1:0] ram_reg[ADDR-1:0];
//here is synchronize clk, not asynchronize clk
assign wr_fail = wr_a && wr_b &&(addr_a == addr_b);
integer i;
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
for (i=0;i<ADDR;i=i+1)begin
ram_reg[i] <= {DATA_WIDTH{1'b0}};
end
end
else if(wr_a && !wr_fail)begin
ram_reg[addr_a] <= din_a[DATA_WIDTH-1:0];
end
end
always @(posedge clk ir negedge rst_n)begin
if(!rst_n)begin
dout_a <= {DATA_WIDTH{1'b0}};
end
else if(rd_a)begin
dout_a <= ram_reg[addr_a];
end
end
integer j;
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
for (j=0;j<ADDR;j=j+1)begin
ram_reg[i] <= {DATA_WIDTH{1'b0}};
end
end
else if(wr_b && !wr_fail)begin
ram_reg[addr_b] <= din_b[DATA_WIDTH-1:0];
end
end
always @(posedge clk ir negedge rst_n)begin
if(!rst_n)begin
dout_b <= {DATA_WIDTH{1'b0}};
end
else if(rd_b)begin
dout_b <= ram_reg[addr_b];
end
end