/*
 * LCD communicates with ILI9341V LCD controller over 4 wire SPI.
 * 
 * When load=1 and in[8]=0 transmission of byte in[7:0] is initiated.
 * CSX is goes low (and stays low even when transmission is completed).
 * DCX is set to in[9]. The byte in[7:0] is send to SDO bitwise together
 * with 8 clock signals on SCK. During transmission out[15] is 1.
 * After 16 clock cycles transmission is completed and out[15] is set to 0.
 * 
 * When load=1 and in[8]=1 CSX goes high and DCX=in[9] without transmission
 * of any bit.
 * 
 * When load16=1 transmission of word in[15:0] is initiated. CSX is goes low
 * (and stays low even when transmission is completed). DCX is set to 1 (data).
 * After 32 clock cycles transmission is completed and out[15] is set to 0.
*/
`default_nettype none

module LCD (
    input wire clk,            // 25 MHz clock
    input wire load,           // Start sending 8-bit command/data
    input wire load16,         // Start sending 16-bit data
    input wire [15:0] in,      // Data to be sent
    output reg [15:0] out,     // Status output
    output reg DCX,            // Data/Command select (1 = data, 0 = command)
    output reg CSX,            // Chip select (active low)
    output reg SDO,            // Serial data out (MOSI)
    output reg SCK             // Serial clock
);

    reg [15:0] shift_reg = 16'b0;
    reg [3:0] bit_counter = 0;
    reg transmitting = 0;
    reg is_16bit = 0;

    initial begin
        CSX <= 1;
        DCX <= 0;
        SCK <= 0;
        SDO <= 0;
    end

    always @(posedge clk) begin
        // Default signal values
        SCK <= 0;
        SDO <= transmitting ? SDO : 0;
        out <= (transmitting || load || load16) ? 16'h8000 : 16'h0000;
        //CSX <= ~transmitting;
        
        // Handle new transmission start
        if ((load || load16) && ~transmitting) begin
            transmitting <= 1;
            bit_counter <= (load16) ? 15 : 7;
            shift_reg <= (load16) ? in : {8'b0, in[7:0]};
            is_16bit <= load16;

            DCX <= (load16) ? 1 : in[9];      // data if load16 or in[9] for load
            CSX <= 0;
            SDO <= (load16) ? in[15] : in[7]; // First bit to send
        end

        // Continue shifting out bits
        else if (transmitting) begin
            SCK <= ~SCK;

            if (SCK == 1) begin
                // Set next bit on falling edge
                SDO <= shift_reg[bit_counter - 1];
                bit_counter <= bit_counter - 1;
            end
            else begin
                // Shift on rising edge
                if (bit_counter == 0 && SCK == 0) begin
                    transmitting <= 0;
                end
            end
        end
    end
endmodule
