70 lines
2.4 KiB
Coq
70 lines
2.4 KiB
Coq
|
|
// 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
|