module cordic_sincos (
    input wire clk,
    input wire rst,
    input wire start,
    input wire [15:0] angle_in,
    output reg [15:0] sin_out,
    output reg [15:0] cos_out,
    output reg done
);

    // Fixed-point Parameters
    // Angle: Q2.14 (Range [-2, 2) covers -pi/2 to pi/2)
    // Sin/Cos: Q1.15 Output
    
    // Internal calculations use Q2.14 to avoid overflow.
    // CORDIC gain 1.64676...
    // Initial X = 1/Gain = 0.60725...
    // In Q2.14: 0.60725 * 16384 = 9949 = 0x26DD
    localparam [15:0] INIT_X = 16'h26DD;
    
    // Internal registers (Q2.14)
    reg signed [15:0] x, y; // Using Q2.14 provides range [-2, 2]
    reg signed [15:0] z;    // Q2.14
    reg [3:0] iter;
    reg [1:0] state; // 0: IDLE, 1: RUN, 2: DONE
    
    localparam S_IDLE = 2'd0;
    localparam S_RUN  = 2'd1;
    localparam S_DONE = 2'd2;

    // ATAN Table (Q2.14)
    reg signed [15:0] atan_table [0:15];
    
    initial begin
        atan_table[0] = 16'h3244; // 0.785398
        atan_table[1] = 16'h1DAC; // 0.463648
        atan_table[2] = 16'h0FAE; // 0.244979
        atan_table[3] = 16'h07F5; // 0.124355
        atan_table[4] = 16'h03FF; // 0.062419
        atan_table[5] = 16'h0200; // 0.031240
        atan_table[6] = 16'h0100; // 0.015624
        atan_table[7] = 16'h0080; // 0.007812
        atan_table[8] = 16'h0040; // 0.003906
        atan_table[9] = 16'h0020; // 0.001953
        atan_table[10] = 16'h0010; // 0.000977
        atan_table[11] = 16'h0008; // 0.000488
        atan_table[12] = 16'h0004; // 0.000244
        atan_table[13] = 16'h0002; // 0.000122
        atan_table[14] = 16'h0001; // 0.000061
        atan_table[15] = 16'h0000; // 0.000031
    end

    // Iteration Loop Logic
    wire signed [15:0] x_shifted = x >>> iter;
    wire signed [15:0] y_shifted = y >>> iter;
    wire signed [15:0] z_atan = atan_table[iter];
    
    wire sign = (z[15] == 1'b0); // Positive or zero
    
    always @(posedge clk) begin
        if (rst) begin
            state <= S_IDLE;
            done <= 0;
            iter <= 0;
            sin_out <= 0;
            cos_out <= 0;
            x <= 0;
            y <= 0;
            z <= 0;
        end else begin
            case (state)
                S_IDLE: begin
                    done <= 0;
                    if (start) begin
                        state <= S_RUN;
                        iter <= 0;
                        x <= INIT_X;
                        y <= 0;
                        z <= angle_in;
                    end
                end
                
                S_RUN: begin
                    if (sign) begin
                        // z >= 0
                        x <= x - y_shifted;
                        y <= y + x_shifted;
                        z <= z - z_atan;
                    end else begin
                        // z < 0
                        x <= x + y_shifted;
                        y <= y - x_shifted;
                        z <= z + z_atan;
                    end
                    
                    if (iter == 15) begin
                        state <= S_DONE;
                    end else begin
                        iter <= iter + 1;
                    end
                end
                
                S_DONE: begin
                    done <= 1;
                    
                    // Convert Q2.14 to Q1.15 with saturation
                    // Saturate to max positive Q1.15 (0x7FFF) if >= 1.0 (0x4000 in Q2.14)
                    // Saturate to min negative Q1.15 (0x8000) if < -1.0 (0xC000 in Q2.14)
                    
                    // Handle Y (Sin)
                    if (y >= $signed(16'h4000)) 
                        sin_out <= 16'h7FFF;
                    else if (y < $signed(16'hC000))
                        sin_out <= 16'h8000;
                    else 
                        sin_out <= (y <<< 1);
                    
                    // Handle X (Cos)
                    if (x >= $signed(16'h4000)) 
                        cos_out <= 16'h7FFF;
                    else if (x < $signed(16'hC000))
                        cos_out <= 16'h8000;
                    else 
                        cos_out <= (x <<< 1);
                    
                    state <= S_IDLE;
                end
            endcase
        end
    end

endmodule
