ice40_iserdes.v 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. /*
  2. * ice40_iserdes.v
  3. *
  4. * vim: ts=4 sw=4
  5. *
  6. * Copyright (C) 2020 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 ice40_iserdes #(
  35. parameter EDGE_SEL = "SINGLE_POS", // "SINGLE_POS" / "SINGLE_NEG" / "DUAL_POS" / "DUAL_POS_NEG"
  36. parameter PHASE_SEL = "STATIC", // "STATIC" / "DYNAMIC"
  37. parameter integer PHASE = 0,
  38. parameter integer SERDES_GRP = 0
  39. )(
  40. input wire [1:0] d,
  41. output wire [3:0] q,
  42. input wire edge_sel,
  43. input wire [1:0] phase_sel,
  44. input wire sync,
  45. input wire clk_1x,
  46. input wire clk_4x
  47. );
  48. genvar i, j;
  49. /* 0 1
  50. * SINGLE_POS POS /
  51. * SINGLE_NEG NEG /
  52. * DUAL_POS POS /
  53. * DUAL_POS_NEG POS NEG
  54. */
  55. // FIXME: The DUAL_POS_NEG mode would need a negative edge sync signal as
  56. // well
  57. // Signals
  58. // -------
  59. wire [3:0] shift_in[0:1];
  60. wire [3:0] shift_out[0:1];
  61. wire [3:0] fcap_in[0:1];
  62. wire [3:0] fcap_out[0:1];
  63. // Fast paths
  64. // ----------
  65. // - For the "SINGLE_{POS,NEG}", we only have a single path
  66. // - For the "DUAL_POS_POS" case it's a single path as well with a pre-sel
  67. // mux. If dynamic phase is also enabled, this option will have an added
  68. // delay (because need for mux between path and between phase)
  69. // - For the "DUAL_POS_NEG" case, we have two independent paths
  70. generate
  71. for (j=0; j<2; j=j+1) begin
  72. if ((j == 0) || (EDGE_SEL == "DUAL_POS_NEG"))
  73. begin : fp
  74. localparam IS_NEG = (EDGE_SEL == "SINGLE_NEG") || (j == 1);
  75. wire edge_active;
  76. wire din_mux;
  77. wire din;
  78. // Edge Select
  79. // -----------
  80. assign edge_active = (EDGE_SEL != "DUAL_POS_NEG") || (edge_sel == j);
  81. if (EDGE_SEL == "DUAL_POS_POS") begin
  82. // Need a pre-mux
  83. (* dont_touch *)
  84. SB_LUT4 #(
  85. .LUT_INIT(16'hFC30)
  86. ) lut_edgemux_I (
  87. .I0(1'b0),
  88. .I1(edge_sel),
  89. .I2(d[0]),
  90. .I3(d[1]), // Fast Path for the neg-edge
  91. .O(din_mux)
  92. );
  93. if (PHASE_SEL == "DYNAMIC")
  94. // If we have dynamic phase, we need the added stage
  95. // for timing
  96. ice40_serdes_dff #(
  97. .NEG(IS_NEG),
  98. .SERDES_GRP( (SERDES_GRP << 8) | 'h4b0 | (j << 4) )
  99. ) dff_edgemux_I (
  100. .d(din_mux),
  101. .q(din),
  102. .c(clk_4x)
  103. );
  104. else
  105. // This mux can be packed with the first shift
  106. // register stage
  107. assign din = din_mux;
  108. end else begin
  109. // Directly from IOB signal
  110. assign din = d[j];
  111. end
  112. // Shifter
  113. // -------
  114. assign shift_in[j] = { shift_out[j][2:0], din };
  115. for (i=0; i<4; i=i+1)
  116. begin
  117. ice40_serdes_dff #(
  118. .NEG(IS_NEG),
  119. .SERDES_GRP( (SERDES_GRP << 8) | 'h4a0 | (j << 4) | i )
  120. ) dff_shift_I (
  121. .d(shift_in[j][i]),
  122. .q(shift_out[j][i]),
  123. .c(clk_4x)
  124. );
  125. end
  126. // Fast Capture
  127. // ------------
  128. // If we have dynamic phase selection, apply the LSB here
  129. if (PHASE_SEL == "DYNAMIC")
  130. assign fcap_in[j] = edge_active ? (phase_sel[0] ? shift_out[j] : shift_in[j]) : 4'h0;
  131. else
  132. assign fcap_in[j] = edge_active ? shift_out[j] : 4'h0;
  133. // Register
  134. for (i=0; i<4; i=i+1)
  135. begin
  136. ice40_serdes_dff #(
  137. .NEG(IS_NEG),
  138. .ENA(1),
  139. .SERDES_GRP( (SERDES_GRP << 8) | 'h490 | (j << 4) | i )
  140. ) dff_shift_I (
  141. .d(fcap_in[j][i]),
  142. .q(fcap_out[j][i]),
  143. .e(sync),
  144. .c(clk_4x)
  145. );
  146. end
  147. end
  148. else
  149. begin
  150. // Dummy
  151. assign fcap_out[j] = 4'h0;
  152. end
  153. end
  154. endgenerate
  155. // Slow Capture
  156. // ------------
  157. generate
  158. if (PHASE_SEL == "STATIC")
  159. begin
  160. // Static Phase
  161. // - - - - - - -
  162. wire [3+PHASE:0] scap_in;
  163. wire [3+PHASE:0] scap_out;
  164. // Input
  165. if (PHASE > 0)
  166. assign scap_in[3+PHASE:4] = scap_out[PHASE-1:0];
  167. assign scap_in[3:0] = fcap_out[0] | fcap_out[1];
  168. // Registers
  169. for (i=0; i<(4+PHASE); i=i+1)
  170. ice40_serdes_dff #(
  171. .SERDES_GRP( (SERDES_GRP << 8) | 'h680 | i )
  172. ) dff_scap_I (
  173. .d(scap_in[i]),
  174. .q(scap_out[i]),
  175. .c(clk_1x)
  176. );
  177. // Output
  178. assign q = scap_out[3+PHASE:PHASE];
  179. end
  180. else
  181. begin
  182. // Dynamic Phase
  183. // - - - - - - -
  184. wire [5:0] scap_in;
  185. wire [5:0] scap_out;
  186. // Input
  187. if (EDGE_SEL == "DUAL_POS_NEG")
  188. begin
  189. // Dual Edge Path
  190. // - - - - - - - -
  191. wire [1:0] scap_pre_or;
  192. // Pre-OR
  193. (* SERDES_GRP=( (SERDES_GRP << 8) | 'h680 | 6 ) *)
  194. (* dont_touch *)
  195. SB_LUT4 #(
  196. .LUT_INIT(16'hFFF0)
  197. ) or_lut_2_I (
  198. .I0(1'b0),
  199. .I1(1'b0),
  200. .I2(fcap_out[1][2]),
  201. .I3(fcap_out[0][2]),
  202. .O(scap_pre_or[0])
  203. );
  204. (* SERDES_GRP=( (SERDES_GRP << 8) | 'h680 | 7 ) *)
  205. (* dont_touch *)
  206. SB_LUT4 #(
  207. .LUT_INIT(16'hFFF0)
  208. ) or_lut_3_I (
  209. .I0(1'b0),
  210. .I1(1'b0),
  211. .I2(fcap_out[1][3]),
  212. .I3(fcap_out[0][3]),
  213. .O(scap_pre_or[1])
  214. );
  215. // Main muxes
  216. (* dont_touch *)
  217. SB_LUT4 #(
  218. .LUT_INIT(16'hFE54)
  219. ) mux_lut_I[3:0] (
  220. .I0(phase_sel[1]),
  221. .I1(fcap_out[1][3:0]),
  222. .I2(fcap_out[0][3:0]),
  223. .I3({scap_out[5:4], scap_pre_or}),
  224. .O(scap_in[3:0])
  225. );
  226. // Save regs
  227. assign scap_in[5:4] = fcap_out[0][1:0] | fcap_out[1][1:0];
  228. end
  229. else
  230. begin
  231. // Single Edge Path
  232. // - - - - - - - - -
  233. assign scap_in = {
  234. fcap_out[0][1:0],
  235. phase_sel[1] ?
  236. { scap_out[5:4], fcap_out[0][3:2] } :
  237. fcap_out[0][3:0]
  238. };
  239. end
  240. // Registers
  241. for (i=0; i<6; i=i+1)
  242. ice40_serdes_dff #(
  243. .SERDES_GRP( (SERDES_GRP << 8) | 'h680 | i )
  244. ) dff_scap_I (
  245. .d(scap_in[i]),
  246. .q(scap_out[i]),
  247. .c(clk_1x)
  248. );
  249. // Output
  250. assign q = scap_out[3:0];
  251. end
  252. endgenerate
  253. endmodule