aboutsummaryrefslogtreecommitdiffstats
path: root/fpga/usrp3/top/e31x/spi_slave.v
blob: d8d48115d11cb40952c01970c24ec57b66e8315f (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
//
// Copyright 2015 Ettus Research LLC
//

`ifndef LOG2
`define LOG2(N) (\
  N < 2 ? 0 : \
  N < 4 ? 1 : \
  N < 8 ? 2 : \
  N < 16 ? 3 : \
  N < 32 ? 4 : \
  N < 64 ? 5 : \
  N < 128 ? 6 : \
  N < 256 ? 7 : \
  N < 512 ? 8 : \
  N < 1024 ? 9 : \
  10)
`endif

module spi_slave
#(
  parameter DEPTH = 64
)
(
  // sys connect
  input              clk,
  input              rst,

  // spi slave port
  input              ss,
  input              mosi,
  output             miso,
  input              sck,

  // parallel data io port
  output             parallel_stb,
  input [DEPTH-1:0]  parallel_din,
  output [DEPTH-1:0] parallel_dout
);
  reg mosi_d, mosi_q;
  reg ss_d, ss_q;
  reg sck_d, sck_q;
  reg sck_old_d, sck_old_q;
  reg miso_d, miso_q;

  reg [DEPTH-1:0] data_d, data_q;
  reg             parallel_stb_d, parallel_stb_q;
  reg [`LOG2(DEPTH)-1:0] bit_ct_d, bit_ct_q;
  reg [DEPTH-1:0] parallel_dout_d, parallel_dout_q;

  assign miso = miso_q;
  assign parallel_stb = parallel_stb_q;
  assign parallel_dout = parallel_dout_q;

  always @(*) begin
    ss_d            = ss;
    mosi_d          = mosi;
    miso_d          = miso_q;
    sck_d           = sck;
    sck_old_d       = sck_q;
    data_d          = data_q;
    parallel_stb_d  = 1'b0;
    bit_ct_d        = bit_ct_q;
    parallel_dout_d = parallel_dout_q;

    if (ss_q) begin
      bit_ct_d = 'h0;
      data_d   = parallel_din;
      miso_d   = data_q[DEPTH-1];
    end
    else begin
      if (!sck_old_q && sck_q) begin // rising edge
        data_d   = {data_q[DEPTH-1-1:0], mosi_q};
        bit_ct_d = bit_ct_q + 1'b1;
        if (bit_ct_q == (DEPTH - 1)) begin
          parallel_dout_d = {data_q[DEPTH-1-1:0], mosi_q};
          parallel_stb_d          = 1'b1;
          data_d          = parallel_din;
        end
      end
      else if (sck_old_q && !sck_q) begin // falling edge
        miso_d = data_q[DEPTH-1];
      end
    end
  end

  always @(posedge clk) begin
    if (rst) begin
      parallel_stb_q          <= 1'b0;
      bit_ct_q        <= 'h0;
      parallel_dout_q <= 'h0;
      miso_q          <= 1'b1;
    end else begin
      parallel_stb_q  <= parallel_stb_d;
      bit_ct_q        <= bit_ct_d;
      parallel_dout_q <= parallel_dout_d;
      miso_q          <= miso_d;
    end

    sck_q     <= sck_d;
    mosi_q    <= mosi_d;
    ss_q      <= ss_d;
    data_q    <= data_d;
    sck_old_q <= sck_old_d;
  end

endmodule