1
\$\begingroup\$

I am trying to design a matrix multiplier using systolic arrays architecture. The inputs are 1D arrays with 2's complement 16bits elements. Here is my code:

 `timescale 1 ns/ 1 ps

module sys_array_tb;

reg reset, clk;
localparam  M = 2;
localparam  N = 2;
localparam  DW = 16;

reg start;
reg signed [DW-1:0] W [M*N-1:0];
reg signed [DW-1:0] X [M*N-1:0];
wire signed [DW*2:0] Y [M-1:0];
wire done;

systolic_array #(.M(M),.N(N), .DW(DW)) uut(.clk(clk), .reset(reset), 
                                    .start(start), .X(X),.W(W),.done(done), .Y());

initial begin
    reset <= 1;
  clk <= 0;
  #3
  reset <= 0;
  #3
  
  

  W = {16'h0234, 16'h1345, 16'h2456, 16'h3567};
  X = {16'h0234, 16'h1345, 16'h2456, 16'h3567};
  
  start = 1;
  #3


  wait(done);
  
  #3

  W = {16'h1234, 16'h2345, 16'h3456, 16'h4567};
  X = {16'h1234, 16'h2345, 16'h3456, 16'h4567};
  
  wait(done);
  
  #3

  W = {16'h2234, 16'h3345, 16'h4456, 16'h5567};
  X = {16'h2234, 16'h3345, 16'h4456, 16'h5567};

   wait(done);
  
  #3

  W = {16'h3234, 16'h4345, 16'h5456, 16'h6567};
  X = {16'h3234, 16'h4345, 16'h5456, 16'h6567};
   
   wait(done);

end

initial begin
    repeat(100)
        #5 clk <= ~clk;
end

initial begin
    $dumpfile("wave.vcd");
    $dumpvars(0, sys_array_tb);
end



endmodule


module systolic_array #(
    parameter M = 2,
    parameter N = 2,
    parameter DW = 16
)
(
  input clk,
  input reset,
  input start, // start of the process
  output reg done,
  
  input signed [DW-1:0] W [M*N-1:0],
  input signed [DW-1:0] X [M*N-1:0],
  output signed [2*DW:0] Y [M-1:0]
);


reg calc_done;

reg signed [DW-1:0] A_reg [M-1:0][N-1:0];
reg signed [DW-1:0] B_reg [M-1:0][N-1:0];
reg signed [2*DW:0] C_reg [M-1:0][N-1:0]; 



integer m,n;
always @(posedge clk) begin
  // initializing
  if(reset) begin
    m = 0;
    n = 0 ;
    calc_done = 0;
    done = 0;
    //  count <= 0;
    for(m=0;m<=2;m=m+1) begin
      for(n=0;n<=2;n=n+1) begin
        A_reg[m][n] = 16'd0;
        B_reg[m][n] = 16'd0;
        C_reg[m][n] = 33'd0;
        end 
      end 
  end
  else begin
    if (start) begin
      // converting 1D array to 2D
      for(m=0;m<=M;m=m+1) begin
        for(n=0;n<=N;n=n+1) begin
          A_reg[m][n] = W[(m*M+n)*16+:16];
          B_reg[m][n] = X[(m*M+n)*16+:16];
          C_reg[m][n] = 33'd0;
        end 
      end

      if(!calc_done) begin
        C_reg[m][n] = res[m][n];
        if(n == N) begin
          n = 0;
            if (m == M) begin
              m = 0;
              calc_done = 1;
            end
            else m = m + 1;
        end
        else n = n + 1;       
      end else if(calc_done) begin
        // converting 2D array to 1D
        for(m=0;m<=2;m=m+1) begin   //run through the rows
          for(n=0;n<=2;n=n+1) begin    //run through the columns
            Y[(m*M+n)*16+:16] = C_reg[m][n];
          end
        end   
        done = 1; 
      end

    end    
  end
end

wire [DW-1:0] a_ins [M-1:0][N:0];
wire [DW-1:0] b_ins [M:0][N-1:0];
wire [2*DW:0] c_outs [M-1:0][N-1:0];
wire [2*DW:0] res [M-1:0][N-1:0];
    

genvar  i,j;
generate
  for (i = 0; i < M; i = i+1) //: Rows
  begin
    for (j = 0; j < N; j = j+1) // : Columns
    begin
      PE #(.DW(DW)) pe (
        .clk(clk),
        .reset(reset),
        .x_i(a_ins[i][j]),
        .y_i(b_ins[i][j]),
        .x_o(a_ins[i][j+1]),
        .y_o(b_ins[i+1][j]),
        .mac(c_outs[i][j])
      );
    end
  end
  for (i = 0; i < M; i = i +1) begin
     assign  a_ins[i][0] = A_reg[i][0];
  end
  for (j = 0; j < N; j = j +1) begin
     assign b_ins[0][j] = B_reg[0][j];
  end
  for (i = 0; i < M; i = i +1) begin
     for (j = 0; j < N; j = j +1) begin
        assign res[i][j] = c_outs[i][j];
     end
  end
endgenerate

endmodule

module PE #(
    parameter DW = 16
)
(
input clk,
input reset,

input signed[DW-1:0] x_i,
input signed[DW-1:0] y_i,

output signed[DW-1:0] x_o,
output signed[DW-1:0] y_o,
output signed[2*DW:0] mac // multiply and accumulate 

);


reg signed[DW-1:0] x_reg,y_reg;
reg signed[2*DW:0] mac_reg;

always @(posedge clk) begin
  if (reset) begin
    x_reg <= 0;
    y_reg <= 0;  
    mac_reg <= 0;
  end else begin
    x_reg <= x_i;
    y_reg <= y_i;
    mac_reg <= mac_reg + (x_reg * y_reg);
  end
end

assign x_o = x_reg;
assign y_o = y_reg;
assign mac = mac_reg;

endmodule

I'm getting the following errors when running the simulation:

A_reg[m][n] = W[(m*M+n)*16+:16];
                        |
ncelab: *E,TYCMPAT (./mult.sv,126|24): assignment operator type check failed (expecting datatype compatible with 'packed array' but found 'unpacked array [15:0] of signed packed array [15:0] of logic' instead).
          A_reg[m][n] = W[(m*M+n)*16+:16];
                        |
ncelab: *W,BNDMEM (./mult.sv,126|24): Memory index out of declared bounds.
          B_reg[m][n] = X[(m*M+n)*16+:16];
                        |
ncelab: *E,TYCMPAT (./mult.sv,127|24): assignment operator type check failed (expecting datatype compatible with 'packed array' but found 'unpacked array [15:0] of signed packed array [15:0] of logic' instead).
          B_reg[m][n] = X[(m*M+n)*16+:16];
                        |
ncelab: *W,BNDMEM (./mult.sv,127|24): Memory index out of declared bounds.
            Y[(m*M+n)*16+:16] = C_reg[m][n];
            |
ncelab: *W,BNDMEM (./mult.sv,146|12): Memory index out of declared bounds.
            Y[(m*M+n)*16+:16] = C_reg[m][n];
                                        |
ncelab: *E,TYCMPAT (./mult.sv,146|40): assignment operator type check failed (expecting datatype compatible with 'unpacked array [15:0] of signed packed array [32:0] of logic' but found 'packed array' instead).

I might miss something obvious, but I'm not sure how get to these datatypes match. Any comments would be appreciated.

\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

To understand the error message, in the following assignment:

      A_reg[m][n] = W[(m*M+n)*16+:16];

set m=n=0:

      A_reg[0][0] = W[0 +: 16];

which is the same as:

      A_reg[0][0] = W[15:0];

That expression for W does not make sense.

With M=N=2, the input declaration resolves to:

input signed [15:0] W [3:0],

That is an array of 4 16-bit values. Let's assume you want the following 4 16-bit assignments:

  A_reg[0][0] = W[0];
  A_reg[0][1] = W[1];
  A_reg[1][0] = W[2];
  A_reg[1][1] = W[3];

Then, this would be the for loop:

  for(m=0;m<=M;m=m+1) begin
    for(n=0;n<=N;n=n+1) begin
      A_reg[m][n] = W[ (2*m) + n ];

This resolves the error message for that line of code.

\$\endgroup\$
0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.