Verilog99题——31-37题(存储相关)

前言

不忘出芯veriloig99题的31-37题是存储相关。

31.名词解释

  • ROM:Read Only Memory,只读存储器。
  • RAM:Random Access Memory,随机存取存储器,可以作手机、电脑的运行内存。
  • SRAM:Static Random-Access Memory,静态随机存取存储器,只要供电数据就会保持,但断电数据就会消失。
  • DRAM:Dynamic Random Access Memory,动态随机存储器,主要原理是利用电容存储电荷的多少来代表一个bit是0还是1,由于晶体管的漏电电流现象,电容会放电,所以要周期性的给电容充电,叫刷新。SRAM不需要刷新也会保持数据丢失,但是两者断电后数据都会消失,称为Volatile Memory。
  • SDRAM:Synchronous Dynamic Random Access Memory,同步动态随机存储器,同步写入和读出数据的DRAM。
  • EEPROM:Electrically Erasable Programmable Read Only Memory,电可擦除可编程只读存储器。
  • DDR:Double Data Synchronous Dynamic Random Access Memory,双倍速率同步动态随机存储器,双倍速率传输的SDRAM,在时钟的上升沿和下降沿都可以进行数据传输。我们电脑的内存条都是DDR芯片。
  • MRAM:Magnetoresistive Random Access Memory,磁阻式随机存取内存,是一种非易失性内存技术,与传统的RAM芯片技术不同,MRAM中的数据不作为电荷或电流流动存储,而是由磁存储元件存储。
  • FLASH: Flash Memory,闪存,非易失性固态存储,如制成内存卡或U盘。

32. 用verilog实现一个深度16,位宽8bit的ROM,初始值等于对应地址加上0xA0

module test32
#(
	parameter WD = 4'd8,			//数据位宽
	parameter DP = 5'd16			//深度
)
(
	input					i_en		,
    input   [ADDR_WD-1:0]	i_addr		,
	output		[WD-1:0]	o_data		
    );
	
    localparam	ADDR_WD = clogb2(DP);	//地址位宽
reg [WD-1:0] buffer [DP-1:0];

integer i;

initial begin
  for (i = 0; i < DP; i = i + 1) begin
	buffer[i] <= i + 8'hA0;
  end
end

assign o_data = i_en ? buffer[i_addr] : 'hz ;

function integer clogb2 (input integer depth);
    begin
        for(clogb2=0; depth>0; clogb2=clogb2+1)
        depth = depth >> 1;
    end
endfunction
    
endmodule

33. 画出SRAM bit cell结构图——6管基本存储电路及其运作原理.

6管基本存储电路

晶体管M1及M2构成一个inverter,M3及M4构成另外一个inverter。这两个inverter的output分别接到另外一个inverter的input而形成一个latch,可以将数据锁存。M5及M6是开关,最常见的架构和用法如图所示,M5和M6是一起开或关的。

连接到M5和M6的gate的信号一般称之为word line(字线,缩写成WL),用来控制SRAM bit cell的开关。M5和M6的漏极是数据读出或写入的端口,一般称之为bit line(位线,缩写成BL)。如图所示,M6接到BL,相对地,M5则接到 BLˉ\bar{BL} 。bit cell的儲存值就是指Q的值。

SRAM的基本单元有3种状态:standby(电路处于空闲),reading(读)与writing(写)。

standby:如果字线(Word Line)没有设置为高电平,那么作为控制用的M5,M6两个晶体管处于断路,把基本单元与位线隔离。由M1-M4组成的两个反相器继续保持其状态。

reading:假定存储的内容为1,即在Q处的电平为高,读周期之初,两根位线预充值为逻辑1,随后字线WL置为高电平,使得晶体管M5与M6通路。然后保存在Q的值会传递给位线BL,并且 BLˉ\bar{BL} 通过M1与M5通路直连到低电平,使其值为逻辑0(即Q的高电平使得晶体管M1通路);在位线BL一侧,晶体管M4与M6形成的通路,把位线BL连接到VDD所代表的逻辑1(M4作为P沟道场效应管,由于栅极加了低电平 Qˉ\bar{Q} 而形成通路)。如果存储的内容为0,相反的电路状态将会使 BLˉ\bar{BL} 为1而BL为0.这样在 BLˉ\bar{BL} 与BL间就会有一个很小的电位差,后续放大电路将会辨识出哪根位线是1哪根是0,从而完成读操作。

writing:写周期之初,把要写入的状态加载到位线。如果要写入0,则设置 BLˉ\bar{BL} 为1且BL为0,随后字线WL加载为高电平,位线的状态被载入SRAM的基本单元。

参考链接:

SRAM的工作原理

转帖:6T SRAM的運作原理

34. 用verilog实现一个单端口sram,深度16,位宽8bit。支持片选,读写请求,要求代码可综合。

module spram_16x8 (
input clk,
input [3:0] addr,
input [7:0] din,
output [7:0] dout,
...
);
...
endmodule

module spram
#(
    parameter WD = 8,       //位宽
    parameter DP = 16       //深度
)
(
    input               clk     ,
    input               cs_n    ,
    input               w_r_n   ,
    input       [AD-1:0]  addr    ,
    input       [WD-1:0]  din     ,
    output  reg [WD-1:0]  dout    
    );
localparam AD = clogb2(DP);
reg [WD-1:0]  buffer  [DP-1:0];

always @(posedge clk) begin
    casex ({cs_n,w_r_n})
        2'b1x: dout <= 'hx;
        2'b01: buffer[addr] <= din;
        2'b00: dout <= buffer[addr];
        default: ;
    endcase
end

function integer clogb2 (input integer depth);
    begin
        for(clogb2=0; depth>1; clogb2=clogb2+1)
        depth = depth >> 1;
    end
endfunction
endmodule

35. 用verilog实现一个同步双端口sram,深度16,位宽8bit。A口读出,B口写入。支持片选,读写请求,要求代码可综合。

module dpram_16x8 (
input clk,
input [3:0] addr_a,
output [7:0] dout_a,
input [7:0] din_b,
input [3:0] addr_b,
...
);
...
endmodule

module sy_dpram
#(
    parameter WD = 8,       //位宽
    parameter DP = 16       //深度
)
(
    input                   clk     , 
    input                   cs_n    ,
    input                   wr_n    ,
    input                   rd_n    ,
    input       [WD-1:0]    din_b   ,       //B口写入
    input       [AD-1:0]    addr_b  ,
    input       [AD-1:0]    addr_a  ,       //A口读出
    output  reg [WD-1:0]    dout_a  
    );

    localparam AD = clogb2(DP);
reg [WD-1:0] buffer [DP-1:0];
/*
always @(posedge clk) begin
    if (!cs_n && !rd_n) begin
        dout_a <= buffer[addr_a];
    end
end

always @(posedge clk) begin
    if (!cs_n && !wr_n) begin
        buffer[addr_b] <= din_b;
    end
end
*/
always @(posedge clk) begin
    casex ({cs_n,wr_n,rd_n})
        3'b1xx: dout_a <= 'hx;
        3'b000: begin   dout_a <= buffer[addr_a]; buffer[addr_b] <= din_b;  end
        3'b001: buffer[addr_b] <= din_b;
        3'b010: dout_a <= buffer[addr_a];
        default: ;
    endcase
end

function integer clogb2 (input integer depth);
    begin
        for(clogb2=0; depth>1; clogb2=clogb2+1)
        depth = depth >> 1;
    end
endfunction
endmodule

36. 用verilog实现一个异步双端口ram,深度16,位宽8bit。A口读出,B口写入。支持片选,读写请求,要求代码可综合。

module dpram_16x8 (
input clk_a,
input [3:0] addr_a,
output [7:0] dout_a,
...
input clk_b,
input [7:0] din_b,
input [3:0] addr_b,
...
);
...
endmodule

module as_dpram
#(
    parameter WD = 8,       //位宽
    parameter DP = 16       //深度
)
(
    input                  clk_a   , 
    input                  rda_n   ,
    input         [AD-1:0] addr_a  , 
    output  reg   [WD-1:0] dout_a  , 

    input                  clk_b   , 
    input                  wrb_n   ,
    input         [WD-1:0] din_b   , 
    input         [AD-1:0] addr_b  , 

    input                  cs_n     
    );
    
    localparam AD = clogb2(DP);
reg [WD-1:0] buffer [DP-1:0];

always @(posedge clk_a) begin
    casex ({cs_n,rda_n})
        2'b1x: dout_a <= 'hx;
        2'b00: dout_a <= buffer[addr_a];
        default: ;
    endcase
end

always @(posedge clk_b) begin
    if (!cs_n && !wrb_n) begin
        buffer[addr_b] <= din_b;
    end
end

function integer clogb2 (input integer depth);
    begin
        for(clogb2=0; depth>1; clogb2=clogb2+1)
        depth = depth >> 1;
    end
endfunction

endmodule

37. 用verilog实现一个同步双端口ram,深度16,位宽8bit。A口可读可写,B口可读可写。支持片选,读写请求,要求代码可综合。

module dpram_16x8 (
input clk,
input [7:0] din_a,
input [3:0] addr_a,
output [7:0] dout_a,
...
input [7:0] din_b,
output [7:0] dout_b,
input [3:0] addr_b,
...
);
...
endmodule

module sy_ture_dpram
#(
    parameter WD = 8,       //数据位宽
    parameter AD = 4        //地址位宽
)
(
    input                  clk     , 
    input                  cs_n    ,

    input                  aw_r_n  ,
    input         [AD-1:0] addr_a  ,
    input         [WD-1:0] din_a   ,
    output  reg   [WD-1:0] dout_a  , 

    input                  bw_r_n  ,
    input         [AD-1:0] addr_b  ,
    input         [WD-1:0] din_b   , 
    output  reg   [WD-1:0] dout_b   
  
    );

localparam  DP = 2**AD;
reg [WD-1:0] buffer [DP-1:0];

always @(posedge clk) begin
    casex ({cs_n,aw_r_n})
        2'b1x: dout_a <= 'hx;
        2'b01: buffer[addr_a] <= din_a;
        2'b00: dout_a <= buffer[addr_a];
        default: ;
    endcase
end

always @(posedge clk) begin
    casex ({cs_n,bw_r_n})
        2'b1x: dout_b <= 'hx;
        2'b01: buffer[addr_b] <= din_b;
        2'b00: dout_b <= buffer[addr_b];
        default: ;
    endcase
end

/* always @(posedge clk) begin
    casex ({cs_n,aw_r_n,bw_r_n})
        3'b1xx: begin dout_a <= 'hx; dout_b <= 'hx; end
        3'b000: begin dout_a <= buffer[addr_a]; dout_b <= buffer[addr_b]; end   //A读B读
        3'b001: begin dout_a <= buffer[addr_a]; buffer[addr_b] <= din_b; end    //A读B写
        3'b010: begin buffer[addr_a] <= din_a; dout_b <= buffer[addr_b]; end    //A写B读
        3'b011: begin                                                           //A写B写
            if (addr_a == addr_b) begin
                buffer[addr_a] <= din_a;
            end else begin
                buffer[addr_a] <= din_a;
                buffer[addr_b] <= din_b;
            end 
        end
        default: ;
    endcase
end */

endmodule

:注释里的描述无法综合出ram块,但是逻辑没有问题。

即将入行的数字IC设计工程师