module systolic_array (
    input  wire       clk,
    input  wire       reset,

    input  wire [3:0] in_left_zero,
    input  wire [3:0] in_left_sign,
    input  wire [7:0] in_top,
    input  wire       reset_accumulators,
    input  wire       copy_accumulator_values_to_out_queue,
    input  wire       restart_out_queue,
    //input wire [2:0] apply_shift_to_out,
    //input wire       apply_relu_to_out,

    output wire [7:0] out
);
    reg  signed [16:0] accumulators      [3:0];
    wire signed [16:0] accumulators_next [3:0];
    reg  signed [16:0] out_queue         [3:0];
    reg          [1:0] out_queue_index;

    integer n;
    // // clocked accumulators[]
    // always @(posedge clk)
    //     for (n = 0; n < 4; n = n + 1)
    //         if (reset | reset_accumulators)
    //             accumulators[n] <= 0;
    //         else
    //             accumulators[n] <= accumulators_next[n];

    // // clocked out_queue[]
    // always @(posedge clk)
    //     for (n = 0; n < 4; n = n + 1)
    //         // if (reset)
    //         //     out_queue[n] <= 0;
    //         // else
    //             if (copy_accumulator_values_to_out_queue)
    //                 out_queue[n]    <= accumulators[n]; //accumulators_next[n];
            
    // // clocked out_queue_index[]
    // always @(posedge clk)
    //     if (reset | restart_out_queue)
    //         out_queue_index <= 0;
    //     else
    //         out_queue_index <= out_queue_index + 1;

    always @(posedge clk)
        for (n = 0; n < 4; n = n + 1) begin
            if (reset | reset_accumulators)
                accumulators[n] <= 0;
            else
                accumulators[n] <= accumulators_next[n];

            if (reset | restart_out_queue)
                out_queue_index <= 0;
            else
                out_queue_index <= out_queue_index + 1;

            if (copy_accumulator_values_to_out_queue)
                out_queue[n]    <= accumulators_next[n];
        end

    genvar i, j;
    generate
    for (j = 0; j < 1; j = j + 1)
        for (i = 0; i < 4; i = i + 1) begin : mac
            wire [16:0] value_curr  = accumulators     [i*1+j];
            wire [16:0] value_next  = accumulators_next[i*1+j];
            wire [16:0] value_queue = out_queue        [i*1+j];
            assign accumulators_next[i*1+j] =
                 reset ? 0 :
                 in_left_zero[i] ? accumulators[i*1+j] + 0 :
                (in_left_sign[i] ? accumulators[i*1+j] - $signed(in_top) :
                                   accumulators[i*1+j] + $signed(in_top));
        end
    endgenerate

    assign out = out_queue[out_queue_index] >> 8;
endmodule