aboutsummaryrefslogtreecommitdiff
path: root/spi_routine.v
blob: 2d22cfe55d97454932e6272a6c46c363de74fcf8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
`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