/* (c) Peter McGoron 2022 * This Source Code Form is subject to the terms of the Mozilla Public * License, v.2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ module spi_slave #( parameter WID = 24, // Width of bits per transaction. parameter WID_LEN = 5, // Length in bits required to store WID parameter POLARITY = 0, parameter PHASE = 0 // 0 = rising-read falling-write, 1 = rising-write falling-read. ) ( input clk, input sck, input ss_L, `ifndef SPI_SLAVE_NO_READ output reg [WID-1:0] from_master, input mosi, `endif `ifndef SPI_SLAVE_NO_WRITE input [WID-1:0] to_master, output miso, `endif output finished, input rdy, output err ); wire ss = !ss_L; reg sck_delay = 0; reg [WID_LEN-1:0] bit_counter = 0; reg ss_delay = 0; reg ready_at_start = 0; `ifndef SPI_SLAVE_NO_WRITE reg [WID-1:0] send_buf = 0; `endif task read_data(); `ifndef SPI_SLAVE_NO_READ from_master <= from_master << 1; from_master[0] <= mosi; `endif endtask task write_data(); `ifndef SPI_SLAVE_NO_WRITE send_buf <= send_buf << 1; miso <= send_buf[WID-1]; `endif endtask task setup_bits(); /* at Mode 00, the transmission starts with * a rising edge, and at mode 11, it starts with a falling * edge. For both modes, these are READs. * * For mode 01 and mode 10, the first action is a WRITE. */ if (POLARITY == PHASE) begin miso <= to_master[WID-1]; send_buf <= to_master << 1; end else begin send_buf <= to_master; end endtask task check_counter(); if (bit_counter == WID) begin err <= ready_at_start; end else begin bit_counter <= bit_counter + 1; end endtask always @ (posedge clk) begin sck_delay <= sck; ss_delay <= ss; case ({ss_delay, ss}) 2'b01: begin // rising edge of SS bit_counter <= 0; finished <= 0; err <= 0; ready_at_start <= rdy; setup_bits(); end 2'b10: begin // falling edge finished <= ready_at_start; end 2'b11: begin case ({sck_delay, sck}) 2'b01: begin // rising edge if (PHASE == 1) begin write_data(); end else begin read_data(); end if (POLARITY == 0) begin check_counter(); end end 2'b10: begin // falling edge if (PHASE == 1) begin read_data(); end else begin write_data(); end if (POLARITY == 1) begin check_counter(); end end default: ; endcase end 2'b00: if (!rdy) begin finished <= 0; err <= 0; end endcase end endmodule