/* verilator lint_off BLKLOOPINIT */
// Object Detection Accelerator — YOLO-style backbone + detection head
module detect_accel #(parameter DW=16, GRID=7, NBOX=2, NCLASS=20, CH=64, F=8)(
    input clk, rst_n, input start,
    // Feature map from backbone CNN (GRID×GRID×CH)
    input signed [DW-1:0] backbone_fm [0:GRID*GRID*CH-1],
    // Detection head weights
    input signed [DW-1:0] det_wt [0:NBOX*(5+NCLASS)*CH-1],
    input signed [DW-1:0] det_bias [0:NBOX*(5+NCLASS)-1],
    // Output: per-grid-cell detections
    output reg signed [DW-1:0] box_x [0:GRID*GRID*NBOX-1],
    output reg signed [DW-1:0] box_y [0:GRID*GRID*NBOX-1],
    output reg signed [DW-1:0] box_w [0:GRID*GRID*NBOX-1],
    output reg signed [DW-1:0] box_h [0:GRID*GRID*NBOX-1],
    output reg signed [DW-1:0] obj_score [0:GRID*GRID*NBOX-1],
    output reg signed [DW-1:0] cls_score [0:GRID*GRID*NCLASS-1],
    output reg [9:0] n_detections,
    output reg done
);
    reg [9:0] grid_idx; reg [3:0] box_idx, cls_idx;
    reg [6:0] ch_idx; reg [3:0] state;
    reg signed [DW*2-1:0] psum;
    reg signed [DW-1:0] raw_out [0:4+NCLASS]; // 5 box params + NCLASS scores
    reg [9:0] det_cnt;
    integer i;
    always_ff @(posedge clk or negedge rst_n) begin
        if(!rst_n) begin state<=0; grid_idx<=0; box_idx<=0; cls_idx<=0; ch_idx<=0; psum<='0; det_cnt<=0; done<=0; n_detections<=0;
            for(i=0;i<GRID*GRID*NBOX;i++) begin box_x[i]<='0; box_y[i]<='0; box_w[i]<='0; box_h[i]<='0; obj_score[i]<='0; end
            for(i=0;i<GRID*GRID*NCLASS;i++) cls_score[i]<='0;
            for(i=0;i<5+NCLASS;i++) raw_out[i]<='0;
        end else case(state)
          0: if(start) begin state<=1; grid_idx<=0; box_idx<=0; ch_idx<=0; psum<='0; end
          1: begin // Compute detection outputs per grid cell per box
                psum <= psum + backbone_fm[grid_idx*CH + ch_idx] * det_wt[box_idx*(5+NCLASS)*CH + cls_idx*CH + ch_idx];
                ch_idx <= ch_idx + 1;
                if(ch_idx >= CH-1) begin ch_idx<=0;
                    raw_out[cls_idx] <= (psum + det_bias[box_idx*(5+NCLASS)+cls_idx]) >>> F;
                    psum <= '0; cls_idx <= cls_idx + 1;
                    if(cls_idx >= 5+NCLASS-1) begin cls_idx<=0;
                        // Post-process: sigmoid on x,y,obj; exp on w,h
                        box_x[grid_idx*NBOX+box_idx]  <= raw_out[0]; // sigmoid simplified
                        box_y[grid_idx*NBOX+box_idx]  <= raw_out[1];
                        box_w[grid_idx*NBOX+box_idx]  <= raw_out[2];
                        box_h[grid_idx*NBOX+box_idx]  <= raw_out[3];
                        obj_score[grid_idx*NBOX+box_idx] <= raw_out[4];
                        for(i=0;i<NCLASS;i++) cls_score[grid_idx*NCLASS+i] <= raw_out[5+i];
                        // Count if above threshold
                        if(raw_out[4] > (1 <<< (F-1))) det_cnt <= det_cnt + 1; // threshold=0.5
                        box_idx <= box_idx + 1;
                        if(box_idx >= NBOX-1) begin box_idx<=0; grid_idx<=grid_idx+1;
                            if(grid_idx >= GRID*GRID-1) state<=2;
                        end
                    end
                end
            end
          2: begin n_detections <= det_cnt; done <= 1; end
        endcase
    end
endmodule