/**
 * SPI controller for W25Q16BV
 * 
 * When load=1 transmission of byte in[7:0] is initiated. The byte is send to
 * MOSI (master out slave in) bitwise together with 8 clock signals on SCK.
 * At the same time the SPI recieves a byte at MISO (master in slave out).
 * Sampling of MISO is done at rising edge of SCK and shiftingis done at
 */ 
`default_nettype none

module SPI(
    input clk,
    input load,
    input [15:0] in,
    output reg [15:0] out,
    output reg CSX,
    output reg SDO,
    input SDI,
    output reg SCK
);

    // Put your code here:
    // 1100 0000 0101 1011
    // 1000 0000 0101 1011
    reg active;
    reg [2:0] bit_index;
    reg [7:0] shift_out;
    reg [7:0] shift_in;
    reg [3:0] count;

    wire is_sample_phase = (count >= 1 && count <= 15 && count[0] == 1);
    wire is_shift_phase  = (count >= 0 && count <= 14 && count[0] == 0);

    initial begin
        SDO <= 0;
        CSX <= 1'b1;
        out <= 16'b0;
        bit_index <= 3'b0;
    end

    always @(posedge clk) begin
        SCK <= 0;

        if (load == 1) begin
            CSX <= 1;
            out <= { 8'b0, in[7:0] };

            if (!in[8]) begin
                active <= 1;
                count <= 0;
                bit_index <= 7; // byte order MSB->LSB
                CSX <= 0;
                out[15] <= 1;

                shift_out[7:0] <= in[7:0];
                SDO <= in[7];
            end
        end
        else if (active==1) begin
            SCK <= ~SCK;

            if (count == 15) begin
                SDO <= 0;
                out <= {8'b0, shift_in};

                active <= 0;
            end else begin
                count <= count + 1;

                if (is_sample_phase) begin
                    bit_index <= bit_index - 1;
                    out[7:0] <= {out[6:0], shift_in[bit_index]};

                    shift_out <= {shift_out[6:0], 1'b0};
                    SDO <= shift_out[6]; // next bit
                end
                
                if (is_shift_phase) begin
                    shift_in[bit_index] <= SDI;
                end
            end
        end
    end
endmodule

