`timescale 1ns/1ps
module Crop #(
    parameter reg [15:0] IN_WIDTH = 1934,
    parameter reg [15:0] IN_HEIGHT = 1086,
    parameter reg [15:0] OFFSET_X = 7,
    parameter reg [15:0] OFFSET_Y = 3,
    parameter reg [15:0] OUT_WIDTH = 640,
    parameter reg [15:0] OUT_HEIGHT = 480,
    parameter reg [4:0] COLOR_DEPTH = 8
) (
    input wire clk,
    input wire reset,

    input wire in_en,
    output wire out_ready,
    output wire out_receive,
    input wire [COLOR_DEPTH - 1:0] in_data[3],

    input wire in_ready,
    input wire in_receive,
    output reg out_en,
    output reg [COLOR_DEPTH - 1:0] out_data[3]
);
  reg [1:0] state, nextState;
  localparam reg [1:0] READ_DATA = 0;
  localparam reg [1:0] HANDLE_DATA = 1;
  localparam reg [1:0] SEND_DATA = 2;

  reg [15:0] cnt_x, cnt_y;
  reg [COLOR_DEPTH - 1:0] data[3];
  wire is_valid;

  // 状态切换
  always @(posedge clk) begin
    if (reset) state <= READ_DATA;
    else state <= nextState;
  end

  // 下一状态更新
  always @(*) begin
    case (state)
      READ_DATA:   nextState = in_en ? HANDLE_DATA : READ_DATA;
      HANDLE_DATA: nextState = SEND_DATA;
      SEND_DATA:   nextState = (is_valid && !in_receive) ? SEND_DATA : READ_DATA;
      default:     nextState = READ_DATA;
    endcase
  end

  assign out_ready = (!in_en && state == READ_DATA && !reset) ? 1 : 0;
  assign out_receive = (in_en && state == READ_DATA && !reset) ? 1 : 0;
  assign is_valid = ((OFFSET_Y <= cnt_y && cnt_y <= (OFFSET_Y + OUT_HEIGHT - 1)) &&
                    (OFFSET_X <= cnt_x && cnt_x <= (OFFSET_X + OUT_WIDTH))) ? 1 : 0;

  always @(posedge clk) begin
    if (reset) begin
      cnt_x <= 0;
      cnt_y <= 0;
      data[0] <= 0;
      data[1] <= 0;
      data[2] <= 0;

      out_en <= 0;
      out_data[0] <= 0;
      out_data[1] <= 0;
      out_data[2] <= 0;
    end else begin
      case (state)
        READ_DATA: begin
          if (in_en) begin
            data[0] <= in_data[0];
            data[1] <= in_data[1];
            data[2] <= in_data[2];
          end
        end

        HANDLE_DATA: begin
          if (cnt_x >= IN_WIDTH - 1) begin
            cnt_x <= 0;
            cnt_y <= cnt_y + 1;
          end else begin
            cnt_x <= cnt_x + 1;
          end
        end

        SEND_DATA: begin
          if (cnt_y >= IN_HEIGHT) begin
            cnt_y <= 0;
          end

          if (in_ready && !in_receive && is_valid) begin
            out_en <= 1;
            out_data[0] <= data[0];
            out_data[1] <= data[1];
            out_data[2] <= data[2];
          end else out_en <= 0;
        end

        default: ;

      endcase
    end
  end

endmodule
