前言
他们都说这一部分不需要自己设计,还说了公司里面这部分都是买的,dft和bist前期就不用介入工作,因为买的IP里面已经集成进去了。如果公司没买IP,都是自己做的,那就需要前期和设计工程师一起交流,留下接口。
仅从设计层面来讲,sram_core.v的复杂程度也挺高的(仅针对小编小白)!所以,这部分打算直接附带码,先不做任何解释!如果后面还想分析,再附!
内部模块 sram_core.v
结合上面的图和下面的代码,理解:sram_core就是在里面例化了8片sram_bist
module sram_core(
//input signals
input hclk,
input sram_clk,
input hresetn,
input sram_wen, // =1 读sram; =0,写sram.8个一起读或者一起写
input [12:0] sram_addr,
input [31:0] sram_wdata_in, //data write into sram when "sram_wen_in" active low
input [3:0] bank0_csn, //两个bank,每个bank有四个片选
input [3:0] bank1_csn,
input bist_en, //BIST test mode
input dft_en, //DFT test mode
//output signals
output [7:0] sram_q0,
output [7:0] sram_q1,
output [7:0] sram_q2,
output [7:0] sram_q3,
output [7:0] sram_q4,
output [7:0] sram_q5,
output [7:0] sram_q6,
output [7:0] sram_q7,
output bist_done, //When "bist_done" is high, it shows BIST test is over.
output [7:0] bist_fail //"bist_fail" shows the results of each sram funtions.
);
//Every sram bist's work state and results output.
wire bist_done0;
wire bist_fail0;
wire bist_done1;
wire bist_fail1;
wire bist_done2;
wire bist_fail2;
wire bist_done3;
wire bist_fail3;
wire bist_done4;
wire bist_fail4;
wire bist_done5;
wire bist_fail5;
wire bist_done6;
wire bist_fail6;
wire bist_done7;
wire bist_fail7;
wire bank0_bistdone;
wire bank1_bistdone;
wire [3:0] bank0_bistfail;
wire [3:0] bank1_bistfail;
//bist finishing state of bank0
assign bank0_bistdone = (bist_done3 && bist_done2) && (bist_done1 && bist_done0);
//bist results of bank0
assign bank0_bistfail = {bist_fail3,bist_fail2,bist_fail1,bist_fail0};
//bist finishing state of bank1
assign bank1_bistdone = (bist_done7 && bist_done6) && (bist_done5 && bist_done4);
//bist results of bank1
assign bank1_bistfail = {bist_fail7,bist_fail6,bist_fail5,bist_fail4};
//--------------------------------------------------------------------------
//the 8 srams results of BIST test and the finishing state
//--------------------------------------------------------------------------
assign bist_done = bank0_bistdone && bank1_bistdone;
assign bist_fail = {bank1_bistfail,bank0_bistfail} ;
//-------------------------------------------------------------------------
//Instance 8 srams and each provides with BIST and DFT functions.
//Bank0 comprises of sram0~sram3, and bank1 comprises of sram4~sram7.
//In each bank, the sram control signals broadcast to each sram, and data
//written per byte into each sram in little-endian style.
//-------------------------------------------------------------------------
//bank0 bank1读写使能以及地址都完全相同,写入的数据也相同
sram_bist u_sram_bist0(
.hclk (hclk),
.sram_clk (sram_clk),
.sram_rst_n (hresetn),
.sram_csn_in (bank0_csn[0]),
.sram_wen_in (sram_wen),
.sram_addr_in (sram_addr),
.sram_wdata_in (sram_wdata_in[7:0]),
.bist_en (bist_en),
.dft_en (dft_en),
.sram_data_out (sram_q0),
.bist_done (bist_done0),
.bist_fail (bist_fail0)
);
sram_bist u_sram_bist1(
.hclk (hclk),
.sram_clk (sram_clk),
.sram_rst_n (hresetn),
.sram_csn_in (bank0_csn[1]),
.sram_wen_in (sram_wen),
.sram_addr_in (sram_addr),
.sram_wdata_in (sram_wdata_in[15:8]),
.bist_en (bist_en),
.dft_en (dft_en),
.sram_data_out (sram_q1),
.bist_done (bist_done1),
.bist_fail (bist_fail1)
);
sram_bist u_sram_bist2(
.hclk (hclk),
.sram_clk (sram_clk),
.sram_rst_n (hresetn),
.sram_csn_in (bank0_csn[2]),
.sram_wen_in (sram_wen),
.sram_addr_in (sram_addr),
.sram_wdata_in (sram_wdata_in[23:16]),
.bist_en (bist_en),
.dft_en (dft_en),
.sram_data_out (sram_q2),
.bist_done (bist_done2),
.bist_fail (bist_fail2)
);
sram_bist u_sram_bist3(
.hclk (hclk),
.sram_clk (sram_clk),
.sram_rst_n (hresetn),
.sram_csn_in (bank0_csn[3]),
.sram_wen_in (sram_wen),
.sram_addr_in (sram_addr),
.sram_wdata_in (sram_wdata_in[31:24]),
.bist_en (bist_en),
.dft_en (dft_en),
.sram_data_out (sram_q3),
.bist_done (bist_done3),
.bist_fail (bist_fail3)
);
sram_bist u_sram_bist4(
.hclk (hclk),
.sram_clk (sram_clk),
.sram_rst_n (hresetn),
.sram_csn_in (bank1_csn[0]),
.sram_wen_in (sram_wen),
.sram_addr_in (sram_addr),
.sram_wdata_in (sram_wdata_in[7:0]),
.bist_en (bist_en),
.dft_en (dft_en),
.sram_data_out (sram_q4),
.bist_done (bist_done4),
.bist_fail (bist_fail4)
);
sram_bist u_sram_bist5(
.hclk (hclk),
.sram_clk (sram_clk),
.sram_rst_n (hresetn),
.sram_csn_in (bank1_csn[1]),
.sram_wen_in (sram_wen),
.sram_addr_in (sram_addr),
.sram_wdata_in (sram_wdata_in[15:8]),
.bist_en (bist_en),
.dft_en (dft_en),
.sram_data_out (sram_q5),
.bist_done (bist_done5),
.bist_fail (bist_fail5)
);
sram_bist u_sram_bist6(
.hclk (hclk),
.sram_clk (sram_clk),
.sram_rst_n (hresetn),
.sram_csn_in (bank1_csn[2]),
.sram_wen_in (sram_wen),
.sram_addr_in (sram_addr),
.sram_wdata_in (sram_wdata_in[23:16]),
.bist_en (bist_en),
.dft_en (dft_en),
.sram_data_out (sram_q6),
.bist_done (bist_done6),
.bist_fail (bist_fail6)
);
sram_bist u_sram_bist7(
.hclk (hclk),
.sram_clk (sram_clk),
.sram_rst_n (hresetn),
.sram_csn_in (bank1_csn[3]),
.sram_wen_in (sram_wen),
.sram_addr_in (sram_addr),
.sram_wdata_in (sram_wdata_in[31:24]),
.bist_en (bist_en),
.dft_en (dft_en),
.sram_data_out (sram_q7),
.bist_done (bist_done7),
.bist_fail (bist_fail7)
);
endmodule
单纯设计这个内部模块,现在真的拿不下!这个sram_core.v下面又例化了sram_bist.v,下面继续上sram_bist.v的文件。
sram_bist.v
到这一部分,突然想起来,有人一直在群里问,你们有memory_bist吗?有人回答,在某个软件下面有自带的ip,用就行。所以这部分,也是套用即可(当然,以后套用肯定要懂得原理呀)!
module sram_bist(
//input signals
input hclk,
input sram_clk,
input sram_rst_n,
input sram_csn_in, //chip select enable
input sram_wen_in, //sram write or read enable; 0:write; 1:read
input[12:0] sram_addr_in,
input[7:0 ] sram_wdata_in,
input bist_en, // MBIST mode
input dft_en, // DFT mode
//output signals
output[7:0 ] sram_data_out,
output bist_done, // 1: test over
output bist_fail // high: MBIST Fail
);
//----------------------------------------------------
//Internal signals connected the sram with bist module
//when "bist_en" active high.
//----------------------------------------------------
wire sram_csn;
wire sram_wen;
wire sram_oen;
wire [12:0] sram_a;
wire [7:0] sram_d;
wire [7:0] data_out;
//Sram output data when "dft_en" active high.
wire [7:0] dft_data;
reg [7:0] dft_data_r;
wire [12:0] sram_addr;
wire [7:0] sram_wdata;
//clock for bist logic, when bist is not work, clock should be 0.
wire bist_clk;
genvar K;
//block sram input when cs is diable for low power design
assign sram_addr = sram_csn_in ? 0 : sram_addr_in;
assign sram_wdata = sram_csn_in ? 0 : sram_wdata_in;
//dft test result
assign dft_data = (sram_d ^ sram_a[7:0]) ^ {sram_csn, sram_wen, sram_oen, sram_a[12:8]};
always @(posedge hclk or negedge sram_rst_n) begin
if(!sram_rst_n)
dft_data_r <= 0;
else if(dft_en)
dft_data_r <= dft_data;
end
//sram data output
assign sram_data_out = dft_en ? dft_data_r : data_out;
// Note: Need to take place the mux using the special library cell
/*
generate for(K = 0; K < 8; K = K+1 )
begin :hold
//BHDBWP7T holdQ (.Z(data_out[K]));
end
endgenerate
*/
//clock for bist logic, when bist is not work, clock should be 0.
// Note: Need to take place the mux using the special library cell
// CKMUX2D2BWP7T U_bist_clk_mux (.I0(1'b0), .I1(hclk), .S(bist_en), .Z(bist_clk));
assign bist_clk = bist_en ? hclk : 1'b0;
// One sram with BIST and DFT function
RA1SH u_RA1SH(
.Q (data_out),
.CLK (sram_clk),
.CEN (sram_csn),
.WEN (sram_wen),
.A (sram_a),
.D (sram_d),
.OEN (sram_oen)
);
mbist_8kx8 u_mbist_8kx8(
.b_clk (bist_clk),
.b_rst_n (sram_rst_n),
.b_te (bist_en),
//--------------------------------------------------------
//All the input signals will be derectly connected to
//the sram input when in normal operation; and when in
//BIST TEST mode, there are some mux in BIST module
//selcting all sram input signals which generated by itself:
//sram controll signals, sram write data, etc.
//--------------------------------------------------------
.addr_fun (sram_addr),
.wen_fun (sram_wen_in),
.cen_fun (sram_csn_in),
.oen_fun (1'b0),
.data_fun (sram_wdata),
.ram_read_out (sram_data_out),
.data_test (sram_d),
.addr_test (sram_a),
.wen_test (sram_wen),
.cen_test (sram_csn),
.oen_test (sram_oen),
.b_done (bist_done),
.b_fail (bist_fail)
);
endmodule
这个sram_bist下面又例化了 RA1SH和mbist_8kx8两个模块,这是最后一层例化了。下面附这两个模块的代码!
mbist_8kx8.v
这个模块,里面的状态机啥的,都值得借鉴,如果有时间,建议抠熟!
module mbist_8kx8
#(parameter WE_WIDTH = 1,
parameter ADDR_WIDTH = 13,
parameter DATA_WIDTH = 8
)
(
//input signals
input b_clk, // bist clock
input b_rst_n, // bist resetn
input b_te, // bist enable
input [(ADDR_WIDTH-1):0] addr_fun,
input [(WE_WIDTH-1):0] wen_fun,
input cen_fun,
input oen_fun,
input [(DATA_WIDTH-1):0] data_fun,
input [(DATA_WIDTH-1):0] ram_read_out,
//output signals
output [(ADDR_WIDTH-1):0] addr_test, // address of test
output [(WE_WIDTH-1):0] wen_test, // writing control of bist test mode
output cen_test, // chip enable control of bist test mode
output oen_test, // output enable control of bist test mode
output [(DATA_WIDTH-1):0] data_test, // data input of bist test mode
output b_done, // output state of bist test mode
// When "bist_done" is high, it shows BIST test is over.
output reg b_fail // output result of sram function
// When "bist_fail" is high, the sram function is wrong;
// else, the sram function is right.
);
//----------------------------------------------------
//Define 27 work states of BIST block for bist test
//----------------------------------------------------
`define IDEL1 5'b00000
`define P1_WRITE0 5'b00001
`define IDEL2 5'b00010
`define P2_READ0 5'b00011
`define P2_COMPARE0 5'b00100
`define P2_WRITE1 5'b00101
`define IDEL3 5'b00110
`define P3_READ1 5'b00111
`define P3_COMPARE1 5'b01000
`define P3_WRITE0 5'b01001
`define P3_READ0 5'b01010
`define P3_COMPARE0 5'b01011
`define P3_WRITE1 5'b01100
`define IDEL4 5'b01101
`define P4_READ1 5'b01110
`define P4_COMPARE1 5'b01111
`define P4_WRITE0 5'b10000
`define IDEL5 5'b10001
`define P5_READ0 5'b10010
`define P5_COMPARE0 5'b10011
`define P5_WRITE1 5'b10100
`define P5_READ1 5'b10101
`define P5_COMPARE1 5'b10110
`define P5_WRITE0 5'b10111
`define IDEL6 5'b11000
`define P6_READ0 5'b11001
`define P6_COMPARE0 5'b11010
// sram address when in bist test mode
reg [(ADDR_WIDTH-1):0] test_addr;
// bist test end signal
reg r_end;
reg r_end_en;
// sram address reset when in bist test mode.
reg test_addr_rst;
// sram read or write enable signal when in bist test mode
reg [(WE_WIDTH-1):0] wen_test_inner;
// bist start to work in IDLE
reg rf_start;
// compare the data read from sram with the data written into sram
// enable signal
reg check_en;
// bist test data source select signal
// "pattern_sel == 1'b0"-----> test_pattern = 32'b0;
// "pattern_sel == 1'b1"-----> test_pattern = 32'b1;
reg pattern_sel;
wire [(DATA_WIDTH-1):0] test_pattern;
reg [4:0] cstate, nstate;
// 1 -- address is goign upward; 0 -- address is going downward
reg up1_down0;
// 1 -- address is stepping; 0 -- address remains
reg count_en;
//-----------------------------------------------------------------
// Combinatorial portion
//-----------------------------------------------------------------
assign b_done = r_end;
assign test_pattern = (pattern_sel == 1'b0) ? {DATA_WIDTH{1'b0}} : {DATA_WIDTH{1'b1}};
//--------------------------------------------------------------------
// The output values of all the mux below will be changed based on the
// sram whether in normal operation or in bist test mode.
//---------------------------------------------------------------------
assign data_test = (b_te == 1'b1) ? test_pattern : data_fun;
assign addr_test = (b_te == 1'b1) ? test_addr : addr_fun;
assign wen_test = (b_te == 1'b1) ? wen_test_inner : wen_fun;
assign cen_test = (b_te == 1'b1) ? 1'b0 : cen_fun;
assign oen_test = (b_te == 1'b1) ? 1'b0 : oen_fun;
//--------------------------------------------------------------------
// Sequential portion
//--------------------------------------------------------------------
//--------------------------------
// Generate bist work end signal.
//--------------------------------
always @(posedge b_clk , negedge b_rst_n) begin
if (b_rst_n == 1'b0)
r_end<=1'b0;
else if (r_end_en == 1'b1)
r_end<= 1'b1;
else
r_end <= 1'b0;
end
//----------------------------------------------------
// Generate the sram test address.
// "test_addr_rst " and "up1_down0" decide the mode of
// variable the address(increment/decrement).
//-----------------------------------------------------
always @(posedge b_clk , negedge b_rst_n) begin
if (b_rst_n == 1'b0)
test_addr <= {ADDR_WIDTH{1'b0}};
else if (b_te == 1'b1)
if (test_addr_rst == 1'b1)
if (up1_down0 == 1'b1)
test_addr<= {ADDR_WIDTH{1'b0}};
else
test_addr<= {ADDR_WIDTH{1'b1}};
else
if (count_en == 1'b1)
if (up1_down0 == 1'b1)
test_addr<= test_addr + 1'b1;
else
test_addr<= test_addr - 1'b1;
end
always @(posedge b_clk , negedge b_rst_n)
if (b_rst_n == 1'b0)
b_fail<=1'b1;
else begin
//---------------------------------------------------------
// When in bist idle1 state, "b_fail" defualt value is "0".
// --------------------------------------------------------
if ((b_te == 1'b1) && (rf_start == 1'b1))
b_fail<= 1'b0;
//------------------------------------------------------------
// "b_fail" value is "1", when data read from sram is different
// from the expected data wirtten into sram.
//--------------------------------------------------------------
if ((b_te == 1'b1) && (check_en == 1'b1) && !(test_pattern == ram_read_out))
b_fail<= 1'b1;
end
//------------------------------------------------------------------------------
// Bist test state machine
// write "0"(initial sram) test_address 0-->1fff
// read "0"------> compare -------->write "1" test_address 1fff-->0
// read "1"------> compare -------->write "0" test_address 0-->1fff
// write "1"------> read "1"-------->compare test_address 1fff-->0
// write "0"------> read "0"-------->compare test_address 0-->1fff
// write "1"------> read "1"-------->compare test_address 1fff-->0
// write "0"------> read "0"-------->compare test_address 0-->1fff
//------------------------------------------------------------------------------
always @(posedge b_clk , negedge b_rst_n) begin
if (b_rst_n == 1'b0)
cstate<=`IDEL1;
else
cstate<= nstate;
end
always @(cstate or b_te or r_end or test_addr) begin
up1_down0 = 1'b1;
count_en = 1'b0;
r_end_en = 1'b0;
pattern_sel = 1'b0;
test_addr_rst = 1'b0;
rf_start = 1'b0;
check_en = 1'b0;
wen_test_inner = {WE_WIDTH{1'b1}};
nstate = cstate;
case (cstate)
`IDEL1 :
begin
test_addr_rst = 1'b1;
if (b_te == 1'b1 && r_end == 1'b0) begin
nstate = `P1_WRITE0;
rf_start = 1'b1;
end
end
`P1_WRITE0 : //initial sram from addr 0~1fff
begin
count_en = 1'b1;
wen_test_inner = {WE_WIDTH{1'b0}};
pattern_sel = 1'b0;
if (test_addr == {ADDR_WIDTH{1'b1}} ) begin
nstate = `IDEL2;
test_addr_rst = 1'b1;
up1_down0 = 1'b0;
end
end
`IDEL2 :
begin
pattern_sel = 1'b0;
up1_down0 = 1'b0;
test_addr_rst = 1'b1;
nstate = `P2_READ0;
end
`P2_READ0 :
begin
nstate = `P2_COMPARE0;
end
`P2_COMPARE0 : //compare all "0" data after read from addr 0~1fff
begin
pattern_sel = 1'b0;
check_en = 1'b1;
nstate = `P2_WRITE1;
end
`P2_WRITE1 : //all "1" write test from addr 1fff~0
begin
up1_down0 = 1'b0;
count_en = 1'b1;
wen_test_inner = {WE_WIDTH{1'b0}};
pattern_sel = 1'b1;
if (test_addr == {ADDR_WIDTH{1'b0}}) begin
nstate = `IDEL3;
test_addr_rst = 1'b1;
up1_down0 = 1'b1;
end
else
nstate = `P2_READ0;
end
`IDEL3 :
begin
pattern_sel = 1'b1;
test_addr_rst = 1'b1;
nstate = `P3_READ1;
end
`P3_READ1 :
begin
nstate = `P3_COMPARE1;
end
`P3_COMPARE1 : //compare all "1" data after read from addr 1fff~0
begin
pattern_sel = 1'b1;
check_en = 1'b1;
nstate = `P3_WRITE0;
end
`P3_WRITE0 :
begin
wen_test_inner = {WE_WIDTH{1'b0}};
pattern_sel = 1'b0;
nstate = `P3_READ0;
end
`P3_READ0 :
begin
nstate = `P3_COMPARE0;
end
`P3_COMPARE0 :
begin
pattern_sel = 1'b0;
check_en = 1'b1;
nstate = `P3_WRITE1;
end
`P3_WRITE1 :
begin
wen_test_inner = {WE_WIDTH{1'b0}};
pattern_sel = 1'b1;
count_en = 1'b1;
if (test_addr == {ADDR_WIDTH{1'b1}}) begin
nstate = `IDEL4;
test_addr_rst = 1'b1;
end
else
nstate = `P3_READ1;
end
`IDEL4 : // read all data from addr 1fff~0 and compare with write data "1" every time
begin
pattern_sel = 1'b1;
test_addr_rst = 1'b1;
nstate = `P4_READ1;
end
`P4_READ1 :
begin
nstate = `P4_COMPARE1;
end
`P4_COMPARE1 :
begin
pattern_sel = 1'b1;
check_en = 1'b1;
nstate = `P4_WRITE0;
end
`P4_WRITE0 :
begin
wen_test_inner = {WE_WIDTH{1'b0}};
pattern_sel = 1'b0;
count_en = 1'b1;
if (test_addr == {ADDR_WIDTH{1'b1}}) begin
nstate = `IDEL5;
test_addr_rst = 1'b1;
end
else
nstate = `P4_READ1;
end
`IDEL5 : // read all data from addr 1fff~0 and compare with write data "0" every time
begin
pattern_sel = 1'b1;
test_addr_rst = 1'b1;
nstate = `P5_READ0;
end
`P5_READ0 :
begin
nstate = `P5_COMPARE0;
end
`P5_COMPARE0 :
begin
pattern_sel=1'b0;
check_en=1'b1;
nstate = `P5_WRITE1;
end
`P5_WRITE1 :
begin
wen_test_inner = {WE_WIDTH{1'b0}};
pattern_sel = 1'b1;
nstate = `P5_READ1;
end
`P5_READ1 :
begin
nstate = `P5_COMPARE1;
end
`P5_COMPARE1 :
begin
pattern_sel=1'b1;
check_en=1'b1;
nstate = `P5_WRITE0;
end
`P5_WRITE0 :
begin
wen_test_inner = {WE_WIDTH{1'b0}};
pattern_sel = 1'b0;
count_en = 1'b1;
if (test_addr == {ADDR_WIDTH{1'b1}}) begin
nstate = `IDEL6;
test_addr_rst = 1'b1;
end
else
nstate = `P5_READ0;
end
`IDEL6 :
begin
pattern_sel = 1'b0;
test_addr_rst = 1'b1;
nstate = `P6_READ0;
end
`P6_READ0 :
begin
nstate = `P6_COMPARE0;
end
`P6_COMPARE0 :
begin
pattern_sel = 1'b0;
check_en = 1'b1;
count_en = 1'b1;
if (test_addr == {ADDR_WIDTH{1'b1}}) begin
nstate = `IDEL1;
test_addr_rst = 1'b1;
r_end_en = 1'b1;
end
else
nstate = `P6_READ0;
end
default :
begin
nstate = `IDEL1;
test_addr_rst = 1'b1;
end
endcase
end
endmodule
RA1SH.v
module RA1SH ( //8K
Q,
CLK,
CEN,
WEN,
A,
D,
OEN
);
parameter BITS = 8;
parameter word_depth = 8192;
parameter addr_width = 13;
parameter wordx = {BITS{1'bx}};
parameter addrx = {addr_width{1'bx}};
output [BITS-1:0] Q;
input CLK;
input CEN;
input WEN;
input [addr_width-1:0] A;
input [BITS-1:0] D;
input OEN;
reg [BITS-1:0] mem [word_depth-1:0];
reg NOT_CEN;
reg NOT_WEN;
reg NOT_A0;
reg NOT_A1;
reg NOT_A2;
reg NOT_A3;
reg NOT_A4;
reg NOT_A5;
reg NOT_A6;
reg NOT_A7;
reg NOT_A8;
reg NOT_A9;
reg NOT_A10;
reg NOT_A11;
reg NOT_A12;
reg [addr_width-1:0] NOT_A;
reg NOT_D0;
reg NOT_D1;
reg NOT_D2;
reg NOT_D3;
reg NOT_D4;
reg NOT_D5;
reg NOT_D6;
reg NOT_D7;
reg [BITS-1:0] NOT_D;
reg NOT_CLK_PER;
reg NOT_CLK_MINH;
reg NOT_CLK_MINL;
reg LAST_NOT_CEN;
reg LAST_NOT_WEN;
reg [addr_width-1:0] LAST_NOT_A;
reg [BITS-1:0] LAST_NOT_D;
reg LAST_NOT_CLK_PER;
reg LAST_NOT_CLK_MINH;
reg LAST_NOT_CLK_MINL;
wire [BITS-1:0] _Q;
wire _OENi;
wire [addr_width-1:0] _A;
wire _CLK;
wire _CEN;
wire _OEN;
wire _WEN;
wire [BITS-1:0] _D;
wire re_flag;
wire re_data_flag;
reg LATCHED_CEN;
reg LATCHED_WEN;
reg [addr_width-1:0] LATCHED_A;
reg [BITS-1:0] LATCHED_D;
reg CENi;
reg WENi;
reg [addr_width-1:0] Ai;
reg [BITS-1:0] Di;
reg [BITS-1:0] Qi;
reg [BITS-1:0] LAST_Qi;
reg LAST_CLK;
task update_notifier_buses;
begin
NOT_A = {
NOT_A12,
NOT_A11,
NOT_A10,
NOT_A9,
NOT_A8,
NOT_A7,
NOT_A6,
NOT_A5,
NOT_A4,
NOT_A3,
NOT_A2,
NOT_A1,
NOT_A0};
NOT_D = {
NOT_D7,
NOT_D6,
NOT_D5,
NOT_D4,
NOT_D3,
NOT_D2,
NOT_D1,
NOT_D0};
end
endtask
task mem_cycle;
begin
casez({WENi,CENi})
2'b10: begin
read_mem(1,0);
end
2'b00: begin
write_mem(Ai,Di);
read_mem(0,0);
end
2'b?1: ;
2'b1x: begin
read_mem(0,1);
end
2'bx0: begin
write_mem_x(Ai);
read_mem(0,1);
end
2'b0x,
2'bxx: begin
write_mem_x(Ai);
read_mem(0,1);
end
endcase
end
endtask
task update_last_notifiers;
begin
LAST_NOT_A = NOT_A;
LAST_NOT_D = NOT_D;
LAST_NOT_WEN = NOT_WEN;
LAST_NOT_CEN = NOT_CEN;
LAST_NOT_CLK_PER = NOT_CLK_PER;
LAST_NOT_CLK_MINH = NOT_CLK_MINH;
LAST_NOT_CLK_MINL = NOT_CLK_MINL;
end
endtask
task latch_inputs;
begin
LATCHED_A = _A ;
LATCHED_D = _D ;
LATCHED_WEN = _WEN ;
LATCHED_CEN = _CEN ;
LAST_Qi = Qi;
end
endtask
task update_logic;
begin
CENi = LATCHED_CEN;
WENi = LATCHED_WEN;
Ai = LATCHED_A;
Di = LATCHED_D;
end
endtask
task x_inputs;
integer n;
begin
for (n=0; n<addr_width; n=n+1)
begin
LATCHED_A[n] = (NOT_A[n]!==LAST_NOT_A[n]) ? 1'bx : LATCHED_A[n] ;
end
for (n=0; n<BITS; n=n+1)
begin
LATCHED_D[n] = (NOT_D[n]!==LAST_NOT_D[n]) ? 1'bx : LATCHED_D[n] ;
end
LATCHED_WEN = (NOT_WEN!==LAST_NOT_WEN) ? 1'bx : LATCHED_WEN ;
LATCHED_CEN = (NOT_CEN!==LAST_NOT_CEN) ? 1'bx : LATCHED_CEN ;
end
endtask
task read_mem;
input r_wb;
input xflag;
begin
if (r_wb)
begin
if (valid_address(Ai))
begin
Qi=mem[Ai];
end
else
begin
Qi=wordx;
end
end
else
begin
if (xflag)
begin
Qi=wordx;
end
else
begin
Qi=Di;
end
end
end
endtask
task write_mem;
input [addr_width-1:0] a;
input [BITS-1:0] d;
begin
casez({valid_address(a)})
1'b0:
x_mem;
1'b1: mem[a]=d;
endcase
end
endtask
task write_mem_x;
input [addr_width-1:0] a;
begin
casez({valid_address(a)})
1'b0:
x_mem;
1'b1: mem[a]=wordx;
endcase
end
endtask
task x_mem;
integer n;
begin
for (n=0; n<word_depth; n=n+1)
mem[n]=wordx;
end
endtask
task process_violations;
begin
if ((NOT_CLK_PER!==LAST_NOT_CLK_PER) ||
(NOT_CLK_MINH!==LAST_NOT_CLK_MINH) ||
(NOT_CLK_MINL!==LAST_NOT_CLK_MINL))
begin
if (CENi !== 1'b1)
begin
x_mem;
read_mem(0,1);
end
end
else
begin
update_notifier_buses;
x_inputs;
update_logic;
mem_cycle;
end
update_last_notifiers;
end
endtask
function valid_address;
input [addr_width-1:0] a;
begin
valid_address = (^(a) !== 1'bx);
end
endfunction
bufif0 (Q[0], _Q[0], _OENi);
bufif0 (Q[1], _Q[1], _OENi);
bufif0 (Q[2], _Q[2], _OENi);
bufif0 (Q[3], _Q[3], _OENi);
bufif0 (Q[4], _Q[4], _OENi);
bufif0 (Q[5], _Q[5], _OENi);
bufif0 (Q[6], _Q[6], _OENi);
bufif0 (Q[7], _Q[7], _OENi);
buf (_D[0], D[0]);
buf (_D[1], D[1]);
buf (_D[2], D[2]);
buf (_D[3], D[3]);
buf (_D[4], D[4]);
buf (_D[5], D[5]);
buf (_D[6], D[6]);
buf (_D[7], D[7]);
buf (_A[0], A[0]);
buf (_A[1], A[1]);
buf (_A[2], A[2]);
buf (_A[3], A[3]);
buf (_A[4], A[4]);
buf (_A[5], A[5]);
buf (_A[6], A[6]);
buf (_A[7], A[7]);
buf (_A[8], A[8]);
buf (_A[9], A[9]);
buf (_A[10], A[10]);
buf (_A[11], A[11]);
buf (_A[12], A[12]);
buf (_CLK, CLK);
buf (_WEN, WEN);
buf (_OEN, OEN);
buf (_CEN, CEN);
assign _OENi = _OEN;
assign _Q = Qi;
assign re_flag = !(_CEN);
assign re_data_flag = !(_CEN || _WEN);
always @(
NOT_A0 or
NOT_A1 or
NOT_A2 or
NOT_A3 or
NOT_A4 or
NOT_A5 or
NOT_A6 or
NOT_A7 or
NOT_A8 or
NOT_A9 or
NOT_A10 or
NOT_A11 or
NOT_A12 or
NOT_D0 or
NOT_D1 or
NOT_D2 or
NOT_D3 or
NOT_D4 or
NOT_D5 or
NOT_D6 or
NOT_D7 or
NOT_WEN or
NOT_CEN or
NOT_CLK_PER or
NOT_CLK_MINH or
NOT_CLK_MINL
)
begin
process_violations;
end
always @( _CLK )
begin
casez({LAST_CLK,_CLK})
2'b01: begin
latch_inputs;
update_logic;
mem_cycle;
end
2'b10,
2'bx?,
2'b00,
2'b11: ;
2'b?x: begin
x_mem;
read_mem(0,1);
end
endcase
LAST_CLK = _CLK;
end
specify
$setuphold(posedge CLK, CEN, 1.000, 0.500, NOT_CEN);
$setuphold(posedge CLK &&& re_flag, WEN, 1.000, 0.500, NOT_WEN);
$setuphold(posedge CLK &&& re_flag, A[0], 1.000, 0.500, NOT_A0);
$setuphold(posedge CLK &&& re_flag, A[1], 1.000, 0.500, NOT_A1);
$setuphold(posedge CLK &&& re_flag, A[2], 1.000, 0.500, NOT_A2);
$setuphold(posedge CLK &&& re_flag, A[3], 1.000, 0.500, NOT_A3);
$setuphold(posedge CLK &&& re_flag, A[4], 1.000, 0.500, NOT_A4);
$setuphold(posedge CLK &&& re_flag, A[5], 1.000, 0.500, NOT_A5);
$setuphold(posedge CLK &&& re_flag, A[6], 1.000, 0.500, NOT_A6);
$setuphold(posedge CLK &&& re_flag, A[7], 1.000, 0.500, NOT_A7);
$setuphold(posedge CLK &&& re_flag, A[8], 1.000, 0.500, NOT_A8);
$setuphold(posedge CLK &&& re_flag, A[9], 1.000, 0.500, NOT_A9);
$setuphold(posedge CLK &&& re_flag, A[10], 1.000, 0.500, NOT_A10);
$setuphold(posedge CLK &&& re_flag, A[11], 1.000, 0.500, NOT_A11);
$setuphold(posedge CLK &&& re_data_flag, D[0], 1.000, 0.500, NOT_D0);
$setuphold(posedge CLK &&& re_data_flag, D[1], 1.000, 0.500, NOT_D1);
$setuphold(posedge CLK &&& re_data_flag, D[2], 1.000, 0.500, NOT_D2);
$setuphold(posedge CLK &&& re_data_flag, D[3], 1.000, 0.500, NOT_D3);
$setuphold(posedge CLK &&& re_data_flag, D[4], 1.000, 0.500, NOT_D4);
$setuphold(posedge CLK &&& re_data_flag, D[5], 1.000, 0.500, NOT_D5);
$setuphold(posedge CLK &&& re_data_flag, D[6], 1.000, 0.500, NOT_D6);
$setuphold(posedge CLK &&& re_data_flag, D[7], 1.000, 0.500, NOT_D7);
$period(posedge CLK, 3.000, NOT_CLK_PER);
$width(posedge CLK, 1.000, 0, NOT_CLK_MINH);
$width(negedge CLK, 1.000, 0, NOT_CLK_MINL);
(CLK => Q[0])=(1.000, 1.000, 0.500, 1.000, 0.500, 1.000);
(CLK => Q[1])=(1.000, 1.000, 0.500, 1.000, 0.500, 1.000);
(CLK => Q[2])=(1.000, 1.000, 0.500, 1.000, 0.500, 1.000);
(CLK => Q[3])=(1.000, 1.000, 0.500, 1.000, 0.500, 1.000);
(CLK => Q[4])=(1.000, 1.000, 0.500, 1.000, 0.500, 1.000);
(CLK => Q[5])=(1.000, 1.000, 0.500, 1.000, 0.500, 1.000);
(CLK => Q[6])=(1.000, 1.000, 0.500, 1.000, 0.500, 1.000);
(CLK => Q[7])=(1.000, 1.000, 0.500, 1.000, 0.500, 1.000);
(OEN => Q[0])=(1.000, 1.000, 1.000, 1.000, 1.000, 1.000);
(OEN => Q[1])=(1.000, 1.000, 1.000, 1.000, 1.000, 1.000);
(OEN => Q[2])=(1.000, 1.000, 1.000, 1.000, 1.000, 1.000);
(OEN => Q[3])=(1.000, 1.000, 1.000, 1.000, 1.000, 1.000);
(OEN => Q[4])=(1.000, 1.000, 1.000, 1.000, 1.000, 1.000);
(OEN => Q[5])=(1.000, 1.000, 1.000, 1.000, 1.000, 1.000);
(OEN => Q[6])=(1.000, 1.000, 1.000, 1.000, 1.000, 1.000);
(OEN => Q[7])=(1.000, 1.000, 1.000, 1.000, 1.000, 1.000);
endspecify
endmodule
后记
这是AHB-SRAM项目中,内部模块sram_core.v的所有文件,如果需要跳转到查看此项目的架构,请点击跳转
AHB-SRAM简单设计之架构图解
笔者是小白,自学输出过程中,难免有错误,请大家指正!