// Systolic Array Controller — Tile scheduling FSM
module systolic_ctrl #(parameter DW=16, N=8, AW=12)(
    input clk, rst_n, cmd_start,
    input [AW-1:0] m_sz, k_sz, n_sz,
    output cmd_done, output [AW-1:0] status,
    output reg [AW-1:0] a_addr, output reg a_en,
    input signed [DW-1:0] a_rdata, input a_rvalid,
    output reg [AW-1:0] b_addr, output reg b_en,
    input signed [DW-1:0] b_rdata, input b_rvalid,
    output reg [AW-1:0] c_addr, output reg c_en, output reg [DW*N-1:0] c_wdata,
    output sa_en, sa_clr, sa_wl, output signed [DW-1:0] sa_act[0:N-1], output sa_av,
    input [DW*N-1:0] sa_po, input sa_pv
);
    localparam IDLE=0,LOADW=1,COMP=2,DRAIN=3,STORE=4,NEXT=5,DONE=6;
    reg [3:0] st,nst; reg [AW-1:0] tm,tk,tn,row,kcnt; reg [7:0] dcnt;
    always_ff @(posedge clk or negedge rst_n)
        if(!rst_n) begin st<=IDLE; tm<='0; tk<='0; tn<='0; row<='0; kcnt<='0; dcnt<=0; a_addr<='0; b_addr<='0; c_addr<='0; a_en<=0; b_en<=0; c_en<=0; end
        else begin st<=nst;
            case(st) LOADW: if(a_rvalid) a_addr<=a_addr+1;
                COMP: begin a_en<=(kcnt<k_sz); b_en<=(kcnt<k_sz); a_addr<=a_addr+1; b_addr<=b_addr+1; kcnt<=kcnt+1; end
                DRAIN: dcnt<=dcnt+1;
                STORE: begin c_en<=1; c_addr<=c_addr+1; c_wdata<=sa_po; end
                NEXT: begin tn<=tn+N; if(tn+N>=n_sz) begin tn<='0; tm<=tm+N; end kcnt<='0; row<='0; end
            endcase
        end
    always_comb begin nst=st; case(st)
        IDLE: if(cmd_start) nst=LOADW; LOADW: if(row>=N*N-1) nst=COMP;
        COMP: if(kcnt>=k_sz) nst=DRAIN; DRAIN: if(dcnt>=N) nst=STORE;
        STORE: nst=NEXT; NEXT: nst=(tm>=m_sz&&tn>=n_sz)?DONE:LOADW; DONE: nst=IDLE;
    endcase end
    assign sa_en=(st==COMP)||(st==LOADW); assign sa_clr=(st==LOADW)&&(row==0);
    assign sa_wl=(st==LOADW); assign sa_av=(st==COMP);
    assign cmd_done=(st==DONE); assign status={12'd0,st};
    genvar i; generate for(i=0;i<N;i++) assign sa_act[i]=a_rvalid?a_rdata:'0; endgenerate
endmodule