Search code examples
indexingverilogxilinxhdlxilinx-ise

Verilog: Altenative way for indexing signal on the LHS


I'm using Xilinx that uses XST to synthesize my design. I ran into trouble when I write something like someReg[offest*index+:constant] <= someOtherReg;. The error given is 'Variable index is not supported in signal.' What I've gathered after searching online is that indexing a signal that is on the left hand side is not supported by XST synthesis tool.


What I'm wondering is how to realize that logic of indexing the signal without using that syntax. In the example below I'm creating a Matrix multiplier that reuses a 'rowByColumn' multiplier.


Basically at every rising clock edge I'm loading new values to the input of the 'rowByColumn' multiplier and at the next rising clock edge I'm saving the result at a new register. Saving the result at a new register is the main problem I have.


Here is the code that gives the error. Could you give suggestions on ways to solve or work around the problem.

module MatrixSeq(clk,A,B,C);
    // param
    parameter WIDTH = 32;
    parameter ROW_A  = 2;
    parameter COL_A  = 2;
    parameter ROW_B  = 2;
    parameter COL_B  = 2;
    //ports
    input clk;
    input [WIDTH*COL_A*ROW_A-1:0] A;
    input [WIDTH*COL_B*ROW_B-1:0] B;
    output [WIDTH*ROW_A*COL_B-1:0] C;

    // inputs to rowBycol 
    reg signed [WIDTH*COL_A-1:0] currentRowA;
    reg signed [WIDTH*ROW_B-1:0] currentColB;
    reg signed [WIDTH-1:0] rowByColOut;
    wire signed [WIDTH-1:0] rowByColOutWire; // wire to connet to rowByColOut

    // A,B matrix holders
    reg signed [WIDTH*COL_A*ROW_A-1:0] AsigHolder;
    reg signed [WIDTH*COL_B*ROW_B-1:0] BsigHolder;
    reg signed [WIDTH*ROW_A*ROW_B-1:0] CsigHolder; // C = A*B

    // reg signed [WIDTH-1:0] count;
    integer idxA = 0;       // iterates through the rows of A
    integer idxB = 0;       // iterates through the 'rows' of B

    // Indexing Syntax:
    //  signalAdd[some_expression +: some_range];
    //  Resolves to
    //  signalAdd[some_expression + (some_range - 1) : some_expression];

    always @(posedge clk) begin     // assume we have the transpose of matrix B
        currentRowA <= AsigHolder[WIDTH*COL_A*idxA+:WIDTH*COL_A];
        currentColB <= BsigHolder[WIDTH*COL_B+idxB+:WIDTH*COL_B];
        CsigHolder[WIDTH*(idxA*ROW_A+idxB)+:WIDTH] <= rowByColOut;  // Error: 'Variable index is not supported in signal.'
        idxB <= idxB +1;
        if(idxB == ROW_B) begin     // multiply each row of A with every 'row' B
            idxA <= idxA + 1;
            idxB <= 0;
        end else if(idxA == ROW_A) begin
            idxA <= 0;
            idxB <= 0;
        end
    end
    assign rowByColOutWire = rowByColOut;
    rowBycol rowMultColumn (.CLK(clk), .a(currentRowA), .b(currentColB), .y(rowByColOutWire));  // row by column multiplier
    assign C = CsigHolder;

endmodule

Just to be clear the problem is the third line inside the always block that gives the error 'Variable index is not supported in signal.'


Solution

  • If XST doesn't support part-select (+:/-:) and you cannot upgrade to something complaint with IEEE Std 1364-2001, then you will need to do it the 1995 method; bit assignment:

    for(bit_idx = 0; bit_idx < WIDTH*COL_A; bit_idx=bit_idx+1) begin
      currentRowA[idx] <= AsigHolder[WIDTH*COL_A*idxA + bit_idx];
    end
    

    Or two dimensional arrays:

    reg signed [WIDTH*COL_A-1:0] AsigHolder [0:ROW_A-1];
    ...
    
    always @(posedge clk) begin     // assume we have the transpose of matrix B
      currentRowA <= AsigHolder[idxA];
    

    I noticed your idxA and idxB can go out of range. All registers assigned with non-blocking (<=) are updated after evaluation. This means idxB==ROW_B will be evaluated before idxB <= idxB +1 is updated.
    You should have something more like the following:

    if (idxB < ROW_B-1) begin
      idxB <= idxB + 1;
    end
    else begin
      idxB <= 0;
      if (idxA < ROW_A-1) begin
        idxA <= idxA + 1;
      end
      else begin
        idxA <= 0;
      end
    end
    

    Note: by fixing the index assignments, the part-select (+:/-:) may work as the the design cannot reach an out of bound index.