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, output err ); wire ss = !ss_L; reg sck_delay = 0; reg [WID_LEN-1:0] bit_counter = 0; reg ss_delay = 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 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; setup_bits(); end 2'b10: begin // falling edge finished <= 1; 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 if (bit_counter == WID) begin err <= 1; end else begin bit_counter <= bit_counter + 1; end end end 2'b10: begin // falling edge if (PHASE == 1) begin read_data(); end else begin write_data(); end if (POLARITY == 1) begin if (bit_counter == WID) begin err <= 1; end else begin bit_counter <= bit_counter + 1; end end end default: ; endcase end 2'b00: ; endcase end endmodule