spi_simple.v 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. /*
  2. * spi_simple.v
  3. *
  4. * vim: ts=4 sw=4
  5. *
  6. * Copyright (C) 2019 Sylvain Munaut <tnt@246tNt.com>
  7. * All rights reserved.
  8. *
  9. * BSD 3-clause, see LICENSE.bsd
  10. *
  11. * Redistribution and use in source and binary forms, with or without
  12. * modification, are permitted provided that the following conditions are met:
  13. * * Redistributions of source code must retain the above copyright
  14. * notice, this list of conditions and the following disclaimer.
  15. * * Redistributions in binary form must reproduce the above copyright
  16. * notice, this list of conditions and the following disclaimer in the
  17. * documentation and/or other materials provided with the distribution.
  18. * * Neither the name of the <organization> nor the
  19. * names of its contributors may be used to endorse or promote products
  20. * derived from this software without specific prior written permission.
  21. *
  22. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  23. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  24. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  25. * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
  26. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  27. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  28. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  29. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  30. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  31. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  32. */
  33. `default_nettype none
  34. module spi_simple (
  35. // SPI pads
  36. input wire spi_mosi,
  37. output wire spi_miso,
  38. input wire spi_cs_n,
  39. input wire spi_clk,
  40. // Interface
  41. output wire [7:0] addr,
  42. output wire [7:0] data,
  43. output reg first,
  44. output reg last,
  45. output wire strobe,
  46. input wire [7:0] out,
  47. // Clock / Reset
  48. input wire clk,
  49. input wire rst
  50. );
  51. // Signals
  52. // -------
  53. wire spi_cs_n_i;
  54. wire spi_cs_n_r;
  55. wire spi_cs_n_f;
  56. wire spi_clk_r;
  57. wire spi_clk_f;
  58. wire spi_mosi_i;
  59. reg spi_miso_out;
  60. wire spi_miso_oe;
  61. reg [8:0] shift_reg;
  62. reg [7:0] addr_reg;
  63. reg [2:0] bit_cnt;
  64. reg has_byte;
  65. reg addr_done;
  66. reg strobe_addr;
  67. reg strobe_ext;
  68. // IOs
  69. // ---
  70. // IOs
  71. spi_simple_io_in cs_n_io_I (
  72. .pad(spi_cs_n),
  73. .val(spi_cs_n_i),
  74. .rise(spi_cs_n_r),
  75. .fall(spi_cs_n_f),
  76. .clk(clk),
  77. .rst(rst)
  78. );
  79. spi_simple_io_in clk_io_I (
  80. .pad(spi_clk),
  81. .val(),
  82. .rise(spi_clk_r),
  83. .fall(spi_clk_f),
  84. .clk(clk),
  85. .rst(rst)
  86. );
  87. spi_simple_io_in mosi_io_I (
  88. .pad(spi_mosi),
  89. .val(spi_mosi_i),
  90. .rise(),
  91. .fall(),
  92. .clk(clk),
  93. .rst(rst)
  94. );
  95. spi_simple_io_out miso_io_I (
  96. .pad(spi_miso),
  97. .val(spi_miso_out),
  98. .oe(spi_miso_oe),
  99. .clk(clk),
  100. .rst(rst)
  101. );
  102. // Control logic
  103. // -------------
  104. // Output of single byte
  105. assign spi_miso_oe = ~spi_cs_n_i;
  106. always @(posedge clk)
  107. if (spi_cs_n_f)
  108. spi_miso_out <= out[7];
  109. else if (spi_clk_f)
  110. spi_miso_out <= shift_reg[7] & ~(has_byte | addr_done);
  111. // Shift register
  112. always @(posedge clk)
  113. if (spi_cs_n_f)
  114. shift_reg <= { 1'b0, out };
  115. else if (spi_clk_r | spi_cs_n_r)
  116. shift_reg <= { shift_reg[7:0], spi_mosi_i };
  117. // Bit counter
  118. always @(posedge clk)
  119. if (spi_cs_n_f)
  120. bit_cnt <= 0;
  121. else
  122. bit_cnt <= bit_cnt + spi_clk_r;
  123. // Strobes
  124. always @(posedge clk)
  125. if (spi_cs_n_f) begin
  126. // Technically reset isn't needed ... but sharing it should allow
  127. // packing in the same TILE as the other bit using that reset line
  128. has_byte <= 1'b0;
  129. strobe_addr <= 1'b0;
  130. strobe_ext <= 1'b0;
  131. end else begin
  132. has_byte <= (has_byte & ~(spi_clk_r | spi_cs_n_r)) | ((bit_cnt == 3'b111) & spi_clk_r);
  133. strobe_addr <= has_byte & (spi_clk_r | spi_cs_n_r) & ~addr_done;
  134. strobe_ext <= has_byte & (spi_clk_r | spi_cs_n_r) & addr_done;
  135. end
  136. // Address register
  137. always @(posedge clk)
  138. if (spi_cs_n_f)
  139. addr_done <= 1'b0;
  140. else
  141. addr_done <= addr_done | strobe_addr;
  142. always @(posedge clk)
  143. if (strobe_addr)
  144. addr_reg <= shift_reg[8:1];
  145. // Outputs
  146. assign addr = addr_reg;
  147. assign data = shift_reg[8:1];
  148. assign strobe = strobe_ext;
  149. always @(posedge clk)
  150. begin
  151. if (spi_cs_n_f) begin
  152. first <= 1'b1;
  153. last <= 1'b0;
  154. end else begin
  155. first <= first & ~strobe_ext;
  156. last <= last | spi_cs_n_r;
  157. end
  158. end
  159. endmodule // spi
  160. module spi_simple_io_in (
  161. input wire pad,
  162. output wire val,
  163. output reg rise,
  164. output reg fall,
  165. input wire clk,
  166. input wire rst
  167. );
  168. // Signals
  169. wire iob_out;
  170. reg val_i;
  171. // IOB
  172. SB_IO #(
  173. .PIN_TYPE(6'b000000),
  174. .PULLUP(1'b0),
  175. .NEG_TRIGGER(1'b0),
  176. .IO_STANDARD("SB_LVCMOS")
  177. ) cs_n_iob_I (
  178. .PACKAGE_PIN(pad),
  179. .CLOCK_ENABLE(1'b1),
  180. .INPUT_CLK(clk),
  181. // .OUTPUT_CLK(1'b0),
  182. .OUTPUT_ENABLE(1'b0),
  183. .D_OUT_0(1'b0),
  184. .D_OUT_1(1'b0),
  185. .D_IN_0(iob_out),
  186. .D_IN_1()
  187. );
  188. // Value and transition registers
  189. always @(posedge clk or posedge rst)
  190. if (rst) begin
  191. val_i <= 1'b0;
  192. rise <= 1'b0;
  193. fall <= 1'b0;
  194. end else begin
  195. val_i <= iob_out;
  196. rise <= iob_out & ~val_i;
  197. fall <= ~iob_out & val_i;
  198. end
  199. assign val = val_i;
  200. endmodule // spi_simple_io_in
  201. module spi_simple_io_out (
  202. output wire pad,
  203. input wire val,
  204. input wire oe,
  205. input wire clk,
  206. input wire rst
  207. );
  208. SB_IO #(
  209. .PIN_TYPE(6'b101001),
  210. .PULLUP(1'b0),
  211. .NEG_TRIGGER(1'b0),
  212. .IO_STANDARD("SB_LVCMOS")
  213. ) miso_iob_I (
  214. .PACKAGE_PIN(pad),
  215. .CLOCK_ENABLE(1'b1),
  216. .INPUT_CLK(clk),
  217. .OUTPUT_CLK(1'b0),
  218. .OUTPUT_ENABLE(oe),
  219. .D_OUT_0(val),
  220. .D_OUT_1(1'b0),
  221. .D_IN_0(),
  222. .D_IN_1()
  223. );
  224. endmodule // spi_simple_io_out