/* * Simple SPI implementation. * * Intended for on-board SPI flash only and thus the assumptions * below are made with that in-mind. * * - SPI clock runs at half the rate of the WB clock. The 386 will * never be clocked faster than the flash part can handle. * - Polarity and phase fixed according to flash parts: * a) Master data stable on rising edge of clock * b) Slave presents data on falling clock edge + prop delay * - When initiating exchange, will not ack until complete. This is * so ins/outs can be used to string consecutive bytes to/from. * - Async resets in WB are rediculous. Making it sync * * Eventually this will be enhanced to support a DMA WB master to * transfer whole blocks to/from flash. Host programs a block count * (if relavent), memory address (if relavent), block address, and then * triggers a more complex state machine with a command write. * * Read Address: * 0 - Clock new cycle with zero out and return receive holding register value * 1 - Return receive holding register from previous cycle * * Write Address: * 0 - Write transmit shift register and initiate cycle * 1 - Write chip selects */ `define state_IDLE 2'b00 `define state_ACTIVE 2'b01 `define state_ACK 2'b10 module simple_spi ( input wb_rst, input wb_clk, input wb_adr, input [7:0] wb_dat_i, output [7:0] wb_dat_o, input wb_we, input wb_cyc, input wb_stb, output wb_ack, input spi_MISO, output spi_MOSI, output reg spi_CSn, output reg spi_CLK ); // Simple shift in/out registers reg [1:0] state; reg [3:0] count; reg [7:0] rxdata; reg [7:0] txdata; assign spi_MOSI = txdata[7]; // Wishbone output assign wb_dat_o = rxdata; assign wb_ack = (state == `state_ACK) ? 1'b1 : 1'b0; // Simple state machine always @(posedge wb_clk) begin if (wb_rst) begin spi_CSn <= 1'b1; spi_CLK <= 1'b0; state <= `state_IDLE; count <= 4'h0; rxdata <= 8'h00; txdata <= 8'h00; end else begin case (state) `state_IDLE: begin if (wb_cyc & wb_stb) begin if (wb_adr) begin if (wb_we) spi_CSn <= wb_dat_i[0]; state <= `state_ACK; end else begin if (wb_we) txdata <= wb_dat_i; count <= 0; state <= `state_ACTIVE; end end else state <= `state_IDLE; end `state_ACK : state <= (wb_stb & wb_cyc) ? `state_ACK : `state_IDLE; `state_ACTIVE : begin spi_CLK <= ~spi_CLK; if (count == 15) state <= `state_ACK; else count <= count + 1; // Shift out on falling edge // Shift in on rising edge if (spi_CLK) txdata <= { txdata, 1'b0 }; else rxdata <= { rxdata, spi_MISO }; end default : begin spi_CSn <= 1'b1; spi_CLK <= 1'b0; state <= `state_IDLE; count <= 4'h0; rxdata <= 8'h00; txdata <= 8'h00; end endcase end end endmodule