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
|