// SPI mode 0 slave, oversampled in the system clock domain (SCK must stay below about a // tenth of clk). MISO changes a few clk cycles after each SCK falling edge, which leaves // enough margin for the master's next rising edge at 8 MHz SCK with a 120 MHz clk. module spi_slave ( input wire clk, input wire reset, input wire sck, input wire mosi, input wire ss_n, output wire miso, output wire selected, // ss_n asserted (synchronized) output reg rx_valid, // pulse: rx_byte holds a complete byte output reg [7:0] rx_byte, output reg rx_is_first, // rx_byte is the first byte of the transaction input wire [7:0] tx_byte, // sampled when the next byte starts shifting out output reg tx_loaded // pulse: tx_byte was taken ); reg [2:0] sck_history, ss_n_history; reg [1:0] mosi_history; always @(posedge clk) begin sck_history <= {sck_history[1:0], sck}; ss_n_history <= {ss_n_history[1:0], ss_n}; mosi_history <= {mosi_history[0], mosi}; end wire sck_rising = (sck_history[2:1] == 2'b01); wire sck_falling = (sck_history[2:1] == 2'b10); wire mosi_bit = mosi_history[1]; assign selected = ~ss_n_history[1]; reg [2:0] bit_count; reg [6:0] rx_shift; reg [7:0] tx_shift; reg expecting_first; assign miso = tx_shift[7]; always @(posedge clk) begin rx_valid <= 1'b0; tx_loaded <= 1'b0; if (reset || !selected) begin bit_count <= 3'd0; expecting_first <= 1'b1; tx_shift <= 8'h00; // MISO is don't-care during the command byte end else begin if (sck_rising) begin rx_shift <= {rx_shift[5:0], mosi_bit}; bit_count <= bit_count + 3'd1; if (bit_count == 3'd7) begin rx_valid <= 1'b1; rx_byte <= {rx_shift, mosi_bit}; rx_is_first <= expecting_first; expecting_first <= 1'b0; end end if (sck_falling) begin if (bit_count == 3'd0) begin tx_shift <= tx_byte; tx_loaded <= 1'b1; end else begin tx_shift <= {tx_shift[6:0], 1'b0}; end end end end endmodule