You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SystemVerilog矩阵向量乘法模块复位问题:matrix_addr无法清零

复位时matrix_addr无法清零的调试方案

问题描述

我正在编写一款用于矩阵向量乘法的SystemVerilog模块,模块会将数据存入两个存储器。运行教授提供的测试平台时,遇到存储器地址逻辑的调试问题——复位操作无法将matrix_addr清零,求思路或建议。

波形显示:复位信号有效时,matrix_addr并未被置为0。

模块代码

module input_mems #(
 parameter INW=4,
 parameter M=4,
 parameter N=4,
 localparam LOGN = $clog2(N),
 localparam LOGMN = $clog2(M*N)
 )(
 input clk, reset,

 input [INW-1:0] AXIS_TDATA,
 input AXIS_TVALID,
 input AXIS_TLAST,
 input [LOGN:0] AXIS_TUSER,
 output logic AXIS_TREADY,
 output logic input_loaded,
 input done,
 output logic [LOGN-1:0] D,
 input [LOGN-1:0] vector_read_addr,
 output logic [INW-1:0] vector_val,
 output logic [LOGN-1:0] vector_row,
 input [LOGMN-1:0] matrix_read_addr,
 output logic [INW-1:0] matrix_data
 );
   enum {RESET, INM, INV, INL} state, next_state;
   logic [LOGMN-1:0] matrix_addr;
   logic matrix_wr_en;
   logic [LOGN-1:0] vector_addr;
   logic vector_wr_en;
   logic matrix_loaded;
   logic vector_loaded;
   logic new_matrix;
   assign new_matrix = AXIS_TUSER[0];
   logic INM_skip;
   logic [$clog2(N)-1:0] row;
   assign row = AXIS_TUSER[$clog2(N):1];
   logic [INW+$clog2(N)-1:0] vector_cat_in;
   logic [INW+$clog2(N)-1:0] vector_cat_out;
   logic data_ready_INM;
   logic data_ready_INV;

   //fsm 
   //output logic
   always_comb begin
      if(state == RESET) begin
         AXIS_TREADY = 0;
         input_loaded = 0;
      end
      else if(state == INM) begin
         AXIS_TREADY = 1;
         input_loaded = 0;
      end
      else if(state == INV) begin
         AXIS_TREADY = 1;
         input_loaded = 0;
      end
      else if(state == INL) begin
         input_loaded = 1;
         AXIS_TREADY = 0;
      end
      else begin
         AXIS_TREADY = 0;
         input_loaded = 0;
      end
   end

   //next state logic
   always_comb begin
      if((state == RESET) && (reset == 1)) //stay in reset state
         next_state = RESET;
      else if((state == RESET) && (reset == 0)) //exit reset state
         next_state = INM;
      else if((state == INM) && (matrix_loaded == 1)) //matrix is loaded
         next_state = INV;
      else if((state == INM) && (INM_skip == 1)) //new_matrix says reuse matrix
         next_state = INV;
      else if((state == INM) && (matrix_loaded == 0)) //matrix not loaded yet
         next_state = INM;
      else if((state == INV) && (vector_loaded == 1)) //TLAST asserted
         next_state = INL;
      else if((state == INV) && (vector_loaded == 0)) //vector not loaded yet
         next_state = INV;
      else if((state == INL) && (done == 1)) //go back to beginning
         next_state = INM;
      else if((state == INL) && (done == 0)) //data not loaded yet
         next_state = INL;
   end

   //state register
   always_ff @(posedge clk) begin
      if(reset == 1)
         state <= RESET;
      else
         state <= next_state;
   end


   //memory reset
   always_ff @(posedge clk) begin
      if (reset == 1) begin
         vector_addr <= 0;
         D <= 0;  //reset D counter
      end 
      else if (state == INL && next_state == INM) begin
         vector_addr <= 0;
         D <= 0;
     end
   end

   //Matrix memory
memory #(
   .WIDTH(INW),
   .SIZE(M*N)
   )memory_matrix(
   .data_in(AXIS_TDATA),
   .data_out(matrix_data),
   .clk(clk),
   .addr(matrix_addr),
   .wr_en(matrix_wr_en));

   //Vector memory
memory#(
   .WIDTH(INW+$clog2(N)),
   .SIZE(N)
   )memory_vector(
   .data_in(vector_cat_in),
   .data_out(vector_cat_out),
   .clk(clk),
   .addr(vector_addr),
   .wr_en(vector_wr_en));

   //Matrix
   //wr_en signal
   always_comb begin
      if((AXIS_TREADY == 1) && (AXIS_TVALID == 1) && (state == INM))
         matrix_wr_en = 1;
      else
         matrix_wr_en = 0;
   end

   //Matrix loaded check
   always_comb begin
      if(reset == 1)
         matrix_loaded = 0;
      else if(matrix_addr == M*N - 1) //修正:地址从0开始,最后一个地址是M*N-1
         matrix_loaded = 1;
      else
         matrix_loaded = 0;
   end

   //new_matrix check
   always_comb begin
      if((AXIS_TREADY == 1) && (AXIS_TVALID == 1) && (state == INM) && (matrix_addr == 0) && (new_matrix == 0))
         INM_skip = 1;
      else
         INM_skip = 0;
   end

   //Vector
   //wr_en signal
   always_comb begin
      if((AXIS_TREADY == 1) && (AXIS_TVALID == 1) && (state == INV))
         vector_wr_en = 1;
      else
         vector_wr_en = 0;
   end

   //Vector address
   always_ff @(posedge clk) begin
      if(reset == 1)
         vector_addr <= 0;
      else if(vector_wr_en == 1)
         vector_addr <= vector_addr + 1;
      else
         vector_addr <= vector_addr;
   end
 
   //Vector loaded check
   always_comb begin
      if(reset == 1)
         vector_loaded = 0;
      else if(AXIS_TLAST == 1) //TLAST signal
         vector_loaded = 1;
      else
         vector_loaded = 0;
   end

   //Vector Data Concat.
   always_comb begin
      vector_cat_in = {AXIS_TDATA, row};
   end

   //D Counter
   always_ff @(posedge clk) begin
      if(reset == 1)
         D <= 0;
      else if((AXIS_TREADY == 1) && (AXIS_TVALID == 1) && (state == INV) && (AXIS_TDATA != 0))
         D <= D + 1;
      else
         D <= D;
   end

   //Vector Read
   always_ff @(posedge clk) begin
      if(input_loaded == 1) begin
         vector_addr <= vector_read_addr;
         vector_val <= vector_cat_out[INW+$clog2(N)-1:$clog2(N)]; // Select INW upper bits
         vector_row <= vector_cat_out[$clog2(N)-1:0]; // Select $clog2(N) lower bits
      end
      else
         vector_addr <= vector_addr;
   end

   // 合并后的matrix_addr驱动逻辑
   always_ff @(posedge clk) begin
      if (reset == 1) begin
          matrix_addr <= 0;
      end else if (input_loaded == 1) begin
          matrix_addr <= matrix_read_addr;
      end else if (matrix_wr_en == 1) begin
          matrix_addr <= matrix_addr + 1;
      end else begin
          matrix_addr <= matrix_addr;
      end
   end

endmodule

核心问题与修复思路

  • 多驱动冲突:原代码中matrix_addr被三个独立的always_ff块驱动,这在SystemVerilog中属于非法的多驱动行为,会导致信号值不确定,复位逻辑被覆盖。
  • 合并驱动逻辑:将所有对matrix_addr的操作(复位、读地址赋值、写地址递增)合并到一个always_ff块中,按优先级顺序处理:
    1. 复位信号优先,直接清零
    2. 读模式下(input_loaded=1),赋值为外部输入的读地址
    3. 写模式下(matrix_wr_en=1),地址自增
    4. 其他情况保持原值
  • 额外修正:原matrix_loaded的判断条件错误,将matrix_addr == $clog2(M*N)改为matrix_addr == M*N - 1,因为地址从0开始,MN个存储单元的最后一个地址是MN-1,修正后才能正确判断矩阵是否加载完成。

内容的提问来源于stack exchange,提问作者SeaBass

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 14:45:00