verilog练习:基于 MARCH C+ 算法的SRAM BIST

发布于:2025-02-11 ⋅ 阅读:(17) ⋅ 点赞:(0)

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言


1. 结构图

模块顶层
内部分布

2. 示例代码

2.1 SRAM BIST : MEM_BIST.V

// Author : 
// Revision History : 2020-4-1
// Revision : 1.0
// Email : 
//
`timescale 1ns/1ps

module mem_bist (
   clk,
   rstn,
   error,
   done
);

parameter data_size = 8;
parameter addr_size = 8;
parameter word_depth = 256;

input clk;
input rstn;

output reg error; 
output reg done; 

wire [data_size-1:0] datalock;
wire [addr_size-1:0] a;
wire [data_size-1:0] d;
wire [data_size-1:0] q;
wire wen;
wire cen;

control dut1 (
   .clk(clk),
   .rstn(rstn),
   .wen(wen),
   .cen(cen),
   .addr(a),
   .data(d),
   .datalock(datalock)
);

data_comparator dut2 (
   .clk(clk),
   .rstn(rstn),
   .q(q),
   .datalock(datalock),
   .wen(wen),
   .error(error),
   .done(done)
);

ram dut3 (
   .clk(clk),
   .cen(cen),
   .wen(wen),
   .a(a),
   .d(d),
   .q(q)
);

endmodule

2.1.1 代码分析

代码解释与功能说明
这段代码是一个 Verilog 模块,名为 mem_bist,用于实现一个内存内建自测试(Memory Built-In Self-Test, MBIST)的功能。MBIST 是一种嵌入式系统中常用的测试技术,用于在芯片制造完成后对内存进行自测试,以检测内存是否存在缺陷或故障。

1. 模块定义
module mem_bist (clk, rstn, error, done);
  • clk: 时钟信号,用于同步模块内部的操作。
  • rstn: 异步复位信号,低电平有效。用于初始化模块状态。
  • error: 输出信号,表示测试过程中是否检测到错误。
  • done: 输出信号,表示测试是否完成。
2. 参数定义
parameter data_size = 8;
parameter addr_size = 8;
parameter word_depth = 256;
  • data_size: 数据总线的位宽,设置为 8 位。
  • addr_size: 地址总线的位宽,设置为 8 位。
  • word_depth: 内存的深度(即存储单元的数量),设置为 256 个单元。
3. 信号定义
wire [data_size-1:0] datalock;
wire [addr_size-1:0] a;
wire [data_size-1:0] d;
wire [data_size-1:0] q;
wire wen;
wire cen;
  • datalock: 用于锁定数据的信号,通常用于在测试过程中保持数据的稳定性。
  • a: 地址信号,用于访问内存中的特定存储单元。
  • d: 写入数据信号,用于将数据写入内存。
  • q: 读出数据信号,用于从内存中读取数据。
  • wen: 写使能信号,高电平有效,表示允许写入操作。
  • cen: 芯片使能信号,低电平有效,表示允许内存芯片工作。
4. 子模块实例化
4.1 控制模块 (control)
control dut1 (
              .clk (clk),
              .rstn (rstn),
              .wen (wen),
              .cen (cen),
              .addr (a),
              .data (d),
              .datalock (datalock)
             );
  • control 模块负责生成控制信号,包括地址信号 a、写数据信号 d、写使能信号 wen 和芯片使能信号 cen。
  • datalock 信号用于锁定数据,确保在测试过程中数据的稳定性。
4.2 数据比较模块 (data_comparator)
data_comparator dut2 (
.clk (clk),
.rstn (rstn),
.q (q),
.datalock (datalock),
.wen (wen),
.error (error),
.done (done)
                        );
  • data_comparator 模块负责比较写入的数据和读出的数据,以检测内存是否存在错误。
  • q: 从内存中读取的数据。
  • datalock: 用于锁定数据的信号。
  • wen: 写使能信号。
  • error: 输出信号,表示是否检测到错误。
  • done: 输出信号,表示测试是否完成。
4.3 内存模块 (ram)
ram dut3 (
.clk (clk),
.cen (cen),
.wen (wen),
.a (a),
.d (d),
.q (q)
            );
  • ram 模块是一个简单的内存模块,用于存储数据。
  • clk: 时钟信号。
  • cen: 芯片使能信号。
  • wen: 写使能信号。
  • a: 地址信号。
  • d: 写入数据信号。
  • q: 读出数据信号。
5. 功能描述
5.1 控制模块 (control)
  • 功能: 生成控制信号,包括地址信号 a、写数据信号 d、写使能信号 wen 和芯片使能信号 cen。
  • 工作流程:
    • 在复位信号 rstn 的控制下,初始化所有控制信号。
    • 生成地址信号 a,依次访问内存中的每个存储单元。
    • 生成写数据信号 d,将测试数据写入内存。
    • 生成写使能信号 wen 和芯片使能信号 cen,控制内存的写入操作。
5.2 数据比较模块 (data_comparator)
  • 功能: 比较写入的数据和读出的数据,检测内存是否存在错误。
  • 工作流程:
    • 在复位信号 rstn 的控制下,初始化所有比较逻辑。
    • 读取内存中的数据 q,并与写入的数据 d 进行比较。
    • 如果数据不一致,设置 error 信号为高电平,表示检测到错误。
    • 当所有数据比较完成后,设置 done 信号为高电平,表示测试完成。
5.3 内存模块 (ram)
  • 功能: 存储数据,并根据控制信号进行读写操作。
  • 工作流程:
    • 在时钟信号 clk 的控制下,根据芯片使能信号 cen 和写使能信号 wen 进行读写操作。
    • 当 cen 为低电平且 wen 为高电平时,将写数据信号 d 写入指定地址 a。
    • 当 cen 为低电平且 wen 为低电平时,从指定地址 a 读取数据,并输出到 q。
6. 总体功能

mem_bist 模块通过实例化 control、data_comparator 和 ram 三个子模块,实现了内存内建自测试的功能。具体工作流程如下:

  • 初始化: 在复位信号 rstn 的控制下,初始化所有控制信号和比较逻辑。
  • 写入数据: control 模块生成地址信号 a 和写数据信号 d,并通过 wen 和 cen 控制 ram 模块将数据写入内存。
  • 读取数据: control 模块生成地址信号 a,并通过 cen 控制 ram 模块从内存中读取数据。
  • 数据比较: data_comparator 模块比较读取的数据 q 和写入的数据 d,如果数据不一致,设置 error 信号为高电平。
  • 测试完成: 当所有数据比较完成后,设置 done 信号为高电平,表示测试完成。
7. 应用场景
  • 芯片制造测试: 在芯片制造完成后,使用 MBIST 技术对内存进行自测试,以检测内存是否存在缺陷或故障。
  • 系统级测试: 在嵌入式系统中,使用 MBIST 技术对内存进行定期测试,以确保系统的可靠性和稳定性。
  • 故障诊断: 在系统运行过程中,如果检测到内存错误,可以使用 MBIST 技术进行故障诊断,以确定故障的具体位置。
8. 总结

mem_bist 模块通过实例化 control、data_comparator 和 ram 三个子模块,实现了内存内建自测试的功能。通过生成控制信号、写入数据、读取数据和数据比较,mem_bist 模块能够检测内存是否存在错误,并在测试完成后输出 error 和 done 信号。这种设计方法在芯片制造测试、系统级测试和故障诊断中具有广泛的应用。

2.2 CONTROL.V

// Author :
// Revision History : 2020-4-1
// Revision : 1.0
// Email : 
//
`timescale 1ns/1ps

module control (
   clk,
   rstn,
   wen,
   cen,
   addr,
   data,
   datalock
);

parameter addr_size = 8;
parameter data_size = 8;
parameter word_depth = 256;

input clk;
input rstn;

output wen;
output cen;
output [addr_size-1:0] addr;
output [data_size-1:0] data;
output [data_size-1:0] datalock;

reg wen;
reg cen;
reg [addr_size-1:0] addr;
reg [data_size-1:0] data;
reg [data_size-1:0] datalock;
reg [1:0] pattern;
reg i;
reg [3:0] state;

parameter data_b1 = 8'b0000_0000;
parameter data_b2 = 8'b0000_1111;
parameter data_b3 = 8'b0101_0101;
parameter data_b4 = 8'b0011_0011;

parameter idle = 4'd0,
         s1 = 4'd1,
         s2 = 4'd2,
         s3 = 4'd3,
         s4 = 4'd4,
         s5 = 4'd5,
         s6 = 4'd6,
         updata = 4'd7,
         stop = 4'd8;

always @ (posedge clk or negedge rstn) begin
   if (!rstn) begin
       cen <= 1'b1;
       wen <= 1'b0;
       pattern <= 2'b0;
       data <= data_b1;
       addr <= 8'd0;
       datalock <= 8'd0;
       i <= 1'b0;
       state <= idle;
   end else begin
       case (state)
           idle: begin
               cen <= 1'b0;
               wen <= 1'b0;
               addr <= word_depth-1;
               data <= data_b1;
               pattern <= 2'd0;
               i <= 1'b0;
               state <= s1;
           end
           s1: begin
               if (addr > 8'd0) begin
                   addr <= addr - 8'd1;
                   state <= s1;
               end else begin
                   addr <= 8'd0;
                   wen <= 1'b1;
                   data <= ~data;
                   datalock <= data;
                   state <= s2;
               end
           end
           s2: begin
               if (wen == 0) begin
                   wen <= 1'b1;
                   datalock <= ~datalock;
                   state <= s2;
               end else if (i == 0) begin
                   wen <= 1'b0;
                   i <= 1'b1;
                   state <= s2;
               end else if (addr < word_depth - 1) begin
                   addr <= addr + 8'd1;
                   i <= 1'b0;
                   datalock <= ~datalock;
                   state <= s2;
               end else begin
                   addr <= 8'd0;
                   data <= ~data;
                   state <= s3;
                   i <= 1'b0;
                   datalock <= data;
               end
           end
           s3: begin
               if (wen == 1'b0) begin
                   wen <= 1'b1;
                   datalock <= ~datalock;
                   state <= s3;
               end else if (i == 0) begin
                   wen <= 1'b0;
                   i <= 1'b1;
                   state <= s3;
               end else if (addr < word_depth - 1) begin
                   addr <= addr + 8'd1;
                   i <= 1'b0;
                   datalock <= ~datalock;
                   state <= s3;
               end else begin
                   addr <= word_depth - 1;
                   data <= ~data;
                   i <= 1'b0;
                   datalock <= data;
                   state <= s4;
               end
           end
           s4: begin
               if (wen == 0) begin
                   wen <= 1'b1;
                   datalock <= ~datalock;
                   state <= s4;
               end else if (i == 0) begin
                   wen <= 1'b0;
                   i <= 1'b1;
                   state <= s4;
               end else if (addr > 8'd0) begin
                   addr <= addr - 8'd1;
                   datalock <= ~datalock;
                   i <= 1'b0;
                   state <= s4;
               end else begin
                   addr <= word_depth - 1;
                   data <= ~data;
                   datalock <= data;
                   i <= 1'b0;
                   state <= s5;
               end
           end
           s5: begin
               if (wen == 0) begin
                   wen <= 1'b1;
                   datalock <= ~datalock;
                   state <= s5;
               end else if (i == 0) begin
                   i <= 1'b1;
                   wen <= 1'b0;
                   state <= s5;
               end else if (addr > 8'd0) begin
                   i <= 1'b0;
                   addr <= addr - 8'd1;
                   datalock <= ~datalock;
                   state <= s5;
               end else begin
                   addr <= 8'd0;
                   datalock <= data;
                   state <= s6;
               end
           end
           s6: begin
               if (addr < word_depth - 1) begin
                   addr <= addr + 8'd1;
               end else begin
                   wen <= 0;
                   i <= 0;
                   state <= updata;
               end
           end
           updata: begin
               if (pattern == 0) begin
                   data <= data_b2;
                   pattern <= pattern + 1;
                   state <= s1;
               end else if (pattern == 1) begin
                   data <= data_b3;
                   pattern <= pattern + 1;
                   state <= s1;
               end else if (pattern == 2) begin
                   data <= data_b4;
                   pattern <= pattern + 1;
                   state <= s1;
               end else begin
                   state <= stop;
               end
           end
           stop: begin
               cen <= 1;
           end
           default: state <= idle;
       endcase
   end
end

endmodule

2.2.1功能说明

control 模块通过有限状态机实现了一个内存测试流程,具体步骤如下:

  • 初始化:在复位信号 rstn 的控制下,初始化所有控制信号和状态。
  • 测试模式选择:通过 pattern 寄存器选择不同的测试数据模式。
  • 地址递增/递减:根据当前状态,递增或递减地址 addr,以访问内存中的不同位置。
  • 数据写入:在写使能信号 wen 的控制下,将数据 data 写入内存。
  • 数据锁定:通过 datalock 信号锁定数据,用于后续的比较操作。
  • 状态转换:根据当前状态和条件,转换到下一个状态,继续测试流程。
  • 测试完成:在 stop 状态,设置 cen 信号为高,表示测试完成。

2.3 DATA_COMPATATOR.V

// Author : 
// Revision History : 2020-4-1
// Revision : 1.0
// Email : 
//
`timescale 1ns/1ps

module data_comparator (
   clk,
   rstn,
   datalock,
   wen,
   q,
   error,
   done
);

parameter addr_size = 8,
         data_size = 8,
         word_depth = 256;

input wen;
input [data_size-1:0] datalock;
input clk;
input rstn;
input [data_size-1:0] q;

output error;
output done;

reg error;
reg done;
reg [data_size-1:0] q1;
reg [data_size-1:0] datalock1;

always @ (posedge clk or negedge rstn) begin
   if (!rstn) begin
       error <= 0;
       done <= 0;
       q1 <= 8'd0;
       datalock1 <= 8'd0;
   end else begin
       q1 <= q;
       datalock1 <= datalock;
       if (wen == 1'b1) begin
           if (datalock1 == q1) begin
               error <= 0;
               done <= 1;
           end else begin
               error <= 1;
               done <= 1;
           end
       end else begin
           error <= error;
           done <= done;
       end
   end
end

endmodule

2.3.1 功能说明

data_comparator 模块通过比较从内存读取的数据(q)和预期的锁定数据(datalock),以检测内存测试过程中是否存在错误。具体步骤如下:

  • 初始化:在复位信号 rstn 的控制下,初始化所有输出信号和内部寄存器。
  • 数据存储:在每个时钟周期,将从内存读取的数据(q)和预期的锁定数据(datalock)存储到内部寄存器 q1 和 datalock1。
  • 数据比较:如果 wen 信号为高(表示当前操作是写入),则比较 datalock1 和 q1:
    • 如果数据匹配(datalock1 == q1),则设置 error 为0,表示没有错误,并设置 done 为1,表示测试完成。
    • 如果数据不匹配,则设置 error 为1,表示检测到错误,并设置 done 为1,表示测试完成。
  • 保持状态:如果 wen 信号为低(表示当前操作不是写入),则保持 error 和 done 的当前状态不变。

2.4 波形展示

在这里插入图片描述