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块中,按优先级顺序处理:- 复位信号优先,直接清零
- 读模式下(
input_loaded=1),赋值为外部输入的读地址 - 写模式下(
matrix_wr_en=1),地址自增 - 其他情况保持原值
- 额外修正:原
matrix_loaded的判断条件错误,将matrix_addr == $clog2(M*N)改为matrix_addr == M*N - 1,因为地址从0开始,MN个存储单元的最后一个地址是MN-1,修正后才能正确判断矩阵是否加载完成。
内容的提问来源于stack exchange,提问作者SeaBass
相关产品推荐
相关产品推荐

