module spi_slave (
    // Control/Data Signals,
    input            i_sys_clk,        // FPGA Clock
    output reg       o_rx_data_valid,  // Data Valid pulse (1 clock cycle)
    output reg [7:0] o_rx_byte,        // Byte received on MOSI
    input            i_tx_data_valid,  // Data Valid pulse to register i_tx_byte
    input      [7:0] i_tx_byte,        // Byte to serialize to MISO.

    // SPI Interface
    input      i_spi_sck,
    output reg o_spi_miso,
    input      i_spi_mosi,
    input      i_spi_cs_b
);

  reg [2:0] r_rx_bit_count;
  reg [2:0] r_tx_bit_count;
  reg [7:0] r_temp_rx_byte;
  reg [7:0] r_rx_byte;
  reg r_rx_done;
  reg r2_rx_done;
  reg r3_rx_done;
  reg [7:0] r_tx_byte;

  // Purpose: Recover SPI Byte in SPI Clock Domain
  // Samples line on correct edge of SPI Clock
  always @(posedge i_spi_sck  /* or posedge i_spi_cs_b*/) begin
    if (i_spi_cs_b) begin
      r_rx_bit_count <= 0;
      r_rx_done <= 1'b0;
    end else begin
      r_rx_bit_count <= r_rx_bit_count + 1;
      r_temp_rx_byte <= {r_temp_rx_byte[6:0], i_spi_mosi};

      if (r_rx_bit_count == 3'b111) begin
        r_rx_done <= 1'b1;
        r_rx_byte <= {r_temp_rx_byte[6:0], i_spi_mosi};
      end else if (r_rx_bit_count == 3'b010) begin
        r_rx_done <= 1'b0;
      end
    end
  end



  // Purpose: Cross from SPI Clock Domain to main FPGA clock domain
  // Assert o_rx_data_valid for 1 clock cycle when o_rx_byte has valid data.
  always @(posedge i_sys_clk) begin
    // Here is where clock domains are crossed.
    // This will require timing constraint created, can set up long path.
    r2_rx_done <= r_rx_done;
    r3_rx_done <= r2_rx_done;
    if (r3_rx_done == 1'b0 && r2_rx_done == 1'b1) begin  // rising edge
      o_rx_data_valid <= 1'b1;  // Pulse Data Valid 1 clock cycle
      o_rx_byte <= r_rx_byte;
    end else begin
      o_rx_data_valid <= 1'b0;
    end
  end

  reg [2:0] SCKr;
  always @(posedge i_sys_clk) SCKr <= {SCKr[1:0], i_spi_sck};
  wire SCK_risingedge = (SCKr[2:1] == 2'b01);  // now we can detect SCK rising edges

  // Purpose: Transmits 1 SPI Byte whenever SPI clock is toggling
  // Will transmit read data back to SW over MISO line.
  // Want to put data on the line immediately when CS goes low.
  always @(posedge i_sys_clk) begin
    if (i_spi_cs_b || i_tx_data_valid) begin
      r_tx_byte <= i_tx_byte;
      r_tx_bit_count <= 3'b110;
      o_spi_miso <= i_tx_byte[3'b111];  // Reset to MSb
    end else begin
      if (SCK_risingedge) begin
        r_tx_bit_count <= r_tx_bit_count - 1;
        o_spi_miso <= r_tx_byte[r_tx_bit_count];

        if (r_tx_bit_count == 3'b000) begin
          r_tx_byte <= 8'b00000000;
        end

      end
    end
  end
endmodule  // SPI_Slave
