RAM学习笔记(SRAM,DRAM,同步,异步)
- SRAM和DRAM区别与联系
- 器件结构
- SRAM
- DRAM
- 性能差异
- 使用场景
- SRAM类别与实现
- 同步双端口实现
- 异步双端口实现
SRAM和DRAM区别与联系
从基本的cell结构上划分,RAM分为SRAM和DRAM,二者在性能,成本,使用场景上都有所不同。
器件结构
SRAM
SRAM(Static Random-Access Memory),静态随机存取存储器,其基本的cell电路图如下:
SRAM的cell中共有六个晶体管(transistor)组成,其结构相当于一个SR锁存器:
WL(word line),字线,连接在三极管的栅极,字线用来控制,相当于写使能,当字线接通时,M5,M6打开,位线(Bit Line,图中的BL)才可以进行读写操作,图中有两条位线,互相取反,虽然不是必须两条取反的位线,但是这种取反的位线有助于改善噪声容限。
当栅极电压超过阈值之后,源极的电子才会流通到漏极,使得源极和漏极的电压相等。因此,三极管可以看作一个阀门,阀门打开,阀门两端电压相等,阀门关闭,两端会存在稳定的电势差。
其中,M1与M2,M3与M4分别构成了两个与非门。这里可以验证,以M3和M4组成的与非门为例,在写状态下,BL端输入到Q,因此,
为与非门的输入,与非门的输出为
。锁存器状态具体的细节请参见SR锁存器_个人整理_JauWang,SRAM具体的读写操作讲解请参见SRAM工作原理图解。
DRAM
DRAM cell主要由电容构成,其结构如下:
结构明显简单于SRAM,一个cell只需要一个晶体管和电容,因此其cell面积小于SRAM,集成度可以做得很高。当字线选通时,位线上的电压得以通过晶体管,加在电容上,需要注意的是,电容具有漏电的特性,因此,即使不更新数据,每隔一段时间,DRAM也需要进行刷新一次,保证数据不丢失。同时,电容的充电需要时间,因此,DRAM的读写速度是不如SRAM的。
性能差异
SRAM | DRAM | |
基本元件 | 锁存器 | 电容 |
破坏性读出 | 否 | 是 |
刷新 | 不需要 | 需要 |
读写速度 | 快 | 慢 |
集成度 | 低 | 高 |
发热量 | 大 | 小 |
存储成本 | 高 | 低 |
使用场景
SRAM用于 极高速度信息传送且较小信息量(因为成本问题)场景中,一般CPU的cache使用的就是SRAM,而DRAM则用于大量信息但是速度要求中等情境下,比如内存。
SRAM类别与实现
同步双端口实现
sram共有两个端口,一个为写端口,一个为读端口,代码如下:
`include "defines.v"
module sram_s # (
parameter ADDR_WIDTH = 4,
parameter DATA_WIDTH = 8,
parameter DATA_DEPTH = 16
)(
input wire clk,
input wire rst,
input wire ce,
// port read
input wire[ADDR_WIDTH-1:0] raddr,
input wire re,
output reg[DATA_WIDTH-1:0] rdata,
// port write
input wire[ADDR_WIDTH-1:0] waddr,
input wire we,
input wire[DATA_WIDTH-1:0] wdata
);
integer i;
reg [DATA_WIDTH-1:0] register [DATA_DEPTH-1:0];
always @ (posedge clk) begin
if (rst == `RstEnable) begin
for(i=0; i<DATA_DEPTH; i=i+1) begin
register[i] <= {DATA_WIDTH{1'b0}};
end
end
else if ((we == `WriteEnable) && (ce == `ChipEnable)) begin
register[waddr] <= wdata;
end
end
always @ (posedge clk) begin
if (rst == `RstEnable) begin
rdata <= {DATA_WIDTH{1'b0}};
end
else if ((re == `ReadEnable) && (ce == `ChipEnable)) begin
rdata <= register[raddr];
end else begin
rdata <= rdata;
end
end
endmodule
其中,defines.v文件:
`define RstEnable 1'b1
`define RstDisable 1'b0
`define WriteEnable 1'b1
`define WriteDisable 1'b0
`define ReadEnable 1'b1
`define ReadDisable 1'b0
`define ChipEnable 1'b1
`define ChipDisable 1'b0
testbench文件:
`include "defines.v"
module tb_sram_s(
);
`define CLK_PERIORD 10
parameter ADDR_WIDTH = 4;
parameter DATA_WIDTH = 8;
parameter DATA_DEPTH = 16;
integer i;
reg clk, rst, ce;
reg[ADDR_WIDTH-1:0] raddr;
reg re;
wire[DATA_WIDTH-1:0] rdata;
reg[ADDR_WIDTH-1:0] waddr;
reg we;
reg[DATA_WIDTH-1:0] wdata;
sram_s sram_s_0(
.clk(clk),
.rst(rst),
.ce(ce),
// port read
.raddr(raddr),
.re(re),
.rdata(rdata),
// port write
.waddr(waddr),
.we(we),
.wdata(wdata)
);
initial begin
clk = 0;
end
always #(`CLK_PERIORD/2) clk = ~clk;
initial begin
rst = `RstEnable;
ce = `ChipDisable;
we = `WriteDisable;
re = `ReadDisable;
raddr = {ADDR_WIDTH{1'b0}};
#20
rst = `RstDisable;
ce = `ChipEnable;
#5
@(posedge clk)
we = `WriteEnable;
for (i=0;i<DATA_DEPTH;i=i+1) begin
@(posedge clk)
begin
waddr = i;
wdata = {DATA_WIDTH{1'b0}}+i;
we = `WriteDisable;
re = `ReadEnable;
raddr = i;
end
end
#10
ce = `ChipDisable;
#100 $stop;
end
endmodule
注意其中的@(posedge clk)会阻塞之后的语句直到时钟上升沿到来。在进行仿真时,可能会出现 cannot open include file ‘defines.v’ 的报错,将defines.v文件复制到tb文件所在文件夹下就可以解决。
波形:
电路图中,读输出端口是一个寄存器,如果去掉这个寄存器(即读端口写成组合逻辑),那么读端口的输出随时可以根据读地址的改变而改变,而不是等时钟上升沿才会刷新。
异步双端口实现
不同于同步SRAM,异步双端口SRAM需要两个不同频率的时钟,分别用于两个端口的读写,代码如下:
`include "defines.v"
module sram_a # (
parameter ADDR_WIDTH = 4,
parameter DATA_WIDTH = 8,
parameter DATA_DEPTH = 16
)(
input wire clkr, clkw,
input wire rst,
input wire ce,
// port read
input wire[ADDR_WIDTH-1:0] raddr,
input wire re,
output reg[DATA_WIDTH-1:0] rdata,
// port write
input wire[ADDR_WIDTH-1:0] waddr,
input wire we,
input wire[DATA_WIDTH-1:0] wdata
);
integer i;
reg [DATA_WIDTH-1:0] register [DATA_DEPTH-1:0];
always @ (posedge clkw) begin
if (rst == `RstEnable) begin
for(i=0; i<DATA_DEPTH; i=i+1) begin
register[i] <= {DATA_WIDTH{1'b0}};
end
end
else if ((we == `WriteEnable) && (ce == `ChipEnable)) begin
register[waddr] <= wdata;
end
end
always @ (posedge clkr) begin
if (rst == `RstEnable) begin
rdata <= {DATA_WIDTH{1'b0}};
end
else if ((re == `ReadEnable) && (ce == `ChipEnable)) begin
rdata <= register[raddr];
end else begin
rdata <= rdata;
end
end
endmodule
tb文件:
`include "defines.v"
module tb_sram_a(
);
`define CLK_PERIORD_R 10
`define CLK_PERIORD_W 16
parameter ADDR_WIDTH = 4;
parameter DATA_WIDTH = 8;
parameter DATA_DEPTH = 16;
integer i;
reg clkr, clkw, rst, ce;
reg[ADDR_WIDTH-1:0] raddr;
reg re;
wire[DATA_WIDTH-1:0] rdata;
reg[ADDR_WIDTH-1:0] waddr;
reg we;
reg[DATA_WIDTH-1:0] wdata;
sram_a sram_a_0(
.clkr(clkr),
.clkw(clkw),
.rst(rst),
.ce(ce),
// port read
.raddr(raddr),
.re(re),
.rdata(rdata),
// port write
.waddr(waddr),
.we(we),
.wdata(wdata)
);
initial begin
clkr = 0;
clkw = 0;
end
always #(`CLK_PERIORD_R/2) clkr = ~clkr;
always #(`CLK_PERIORD_W/2) clkw = ~clkw;
initial begin
rst = `RstEnable;
ce = `ChipDisable;
we = `WriteDisable;
re = `ReadDisable;
raddr = {ADDR_WIDTH{1'b0}};
#20
rst = `RstDisable;
ce = `ChipEnable;
#5
@(posedge clkw)
we = `WriteEnable;
for (i=0;i<DATA_DEPTH;i=i+1) begin
@(posedge clkw)
begin
waddr = i;
wdata = {DATA_WIDTH{1'b0}}+i;
end
end
@(posedge clkr)
we = `WriteDisable;
re = `ReadEnable;
for (i=0;i<DATA_DEPTH;i=i+1) begin
@(posedge clkr)
begin
raddr = i;
end
end
#10
ce = `ChipDisable;
#100 $stop;
end
endmodule
仿真波形: