`timescale 1ns / 1ps module spi_routine ( input clk_i, input rst_i, input [31:0] tx_i, output reg [31:0] rx_o, input rd_i, input wr_i, input[7:0] cnt_i, input miso_i, input ss_i, output reg mosi_o, output finish_o, output sclk_o, output next_o ); localparam ADDR_WIDTH = 3; reg [ADDR_WIDTH-1:0] idx = 0; reg [2:0] state = IDLE_S; reg [2:0] next_state; reg [7:0] current_cnt; reg [1:0] sel = 0; reg [31:0] saved_tx; wire [7:0] tx; wire finish_w; localparam READ_S = 3'd2, WRITE_S = 3'd1, IDLE_S = 3'd0; assign tx = ( sel == 0 ? saved_tx[7: 0] : ( sel == 1 ? saved_tx[15: 8] : ( sel == 2 ? saved_tx[23:16] : saved_tx[31:24]))); always @* if( sel == 0 ) saved_tx = tx_i; always @(posedge clk_i, posedge rst_i ) if( rst_i ) state <= IDLE_S; else state <= next_state; always @* begin next_state = state; case( state ) IDLE_S: if( rd_i ) next_state = READ_S; else if( wr_i ) next_state = WRITE_S; READ_S: if( finish_w ) next_state = IDLE_S; WRITE_S: if( finish_w ) next_state = IDLE_S; endcase end always @* if( state == IDLE_S ) begin current_cnt = 0; sel = 0; end always @* mosi_o <= ( state == WRITE_S ? tx[idx] : 1'b1 ); always @( posedge clk_i ) rx_o[idx] <= miso_i; always @( posedge clk_i ) if( state == IDLE_S ) idx <= 2'd0; else idx <= idx + 2'd1; always @( posedge clk_i ) if( idx == 7 ) begin current_cnt <= current_cnt + 1; sel <= sel + 1; end assign finish_w = ( state != IDLE_S && current_cnt == cnt_i ? 1 : 0 ); assign finish_o = finish_w; assign sclk_o = clk_i; assign next_o = ( state != IDLE_S && sel == 3 && current_cnt != cnt_i-1 ? 1 : 0 ); endmodule