mmcme2_drp_func.h 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830
  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Company: Xilinx
  4. // Engineer: Jim Tatsukawa, Karl Kurbjun and Carl Ribbing
  5. // Updated by Marc Defossez
  6. // Date: 19 Sep 2018
  7. // Design Name: MMCME2 DRP
  8. // Module Name: mmcme2_drp_func.h
  9. // Version: 1.31
  10. // Target Devices: 7 Series
  11. // Tool versions: 2014.3 or later
  12. // Description: This header provides the functions necessary to
  13. // calculate the DRP register values for the V6 MMCM.
  14. //
  15. // Revision Notes:
  16. // 3/12 - Updating lookup_low/lookup_high (CR)
  17. // 4/13 - Fractional divide function in mmcm_frac_count_calc function. CRS610807
  18. // 10/24 - Adjusting settings for clarity
  19. // 19 Sep 18 - Update of CP_RES_LFHF tables -- CR1010263
  20. //
  21. // Disclaimer: XILINX IS PROVIDING THIS DESIGN, CODE, OR
  22. // INFORMATION "AS IS" SOLELY FOR USE IN DEVELOPING
  23. // PROGRAMS AND SOLUTIONS FOR XILINX DEVICES. BY
  24. // PROVIDING THIS DESIGN, CODE, OR INFORMATION AS
  25. // ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE,
  26. // APPLICATION OR STANDARD, XILINX IS MAKING NO
  27. // REPRESENTATION THAT THIS IMPLEMENTATION IS FREE
  28. // FROM ANY CLAIMS OF INFRINGEMENT, AND YOU ARE
  29. // RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY
  30. // REQUIRE FOR YOUR IMPLEMENTATION. XILINX
  31. // EXPRESSLY DISCLAIMS ANY WARRANTY WHATSOEVER WITH
  32. // RESPECT TO THE ADEQUACY OF THE IMPLEMENTATION,
  33. // INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR
  34. // REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE
  35. // FROM CLAIMS OF INFRINGEMENT, IMPLIED WARRANTIES
  36. // OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  37. // PURPOSE.
  38. //
  39. // (c) Copyright 2009-2010 Xilinx, Inc.
  40. // All rights reserved.
  41. //
  42. ///////////////////////////////////////////////////////////////////////////////
  43. // These are user functions that should not be modified. Changes to the defines
  44. // or code within the functions may alter the accuracy of the calculations.
  45. // Define debug to provide extra messages durring elaboration
  46. `define DEBUG 1
  47. // FRAC_PRECISION describes the width of the fractional portion of the fixed
  48. // point numbers. These should not be modified, they are for development
  49. // only
  50. `define FRAC_PRECISION 10
  51. // FIXED_WIDTH describes the total size for fixed point calculations(int+frac).
  52. // Warning: L.50 and below will not calculate properly with FIXED_WIDTHs
  53. // greater than 32
  54. `define FIXED_WIDTH 32
  55. // This function takes a fixed point number and rounds it to the nearest
  56. // fractional precision bit.
  57. function [`FIXED_WIDTH:1] round_frac
  58. (
  59. // Input is (FIXED_WIDTH-FRAC_PRECISION).FRAC_PRECISION fixed point number
  60. input [`FIXED_WIDTH:1] decimal,
  61. // This describes the precision of the fraction, for example a value
  62. // of 1 would modify the fractional so that instead of being a .16
  63. // fractional, it would be a .1 (rounded to the nearest 0.5 in turn)
  64. input [`FIXED_WIDTH:1] precision
  65. );
  66. begin
  67. `ifdef DEBUG
  68. $display("round_frac - decimal: %h, precision: %h", decimal, precision);
  69. `endif
  70. // If the fractional precision bit is high then round up
  71. if( decimal[(`FRAC_PRECISION-precision)] == 1'b1) begin
  72. round_frac = decimal + (1'b1 << (`FRAC_PRECISION-precision));
  73. end else begin
  74. round_frac = decimal;
  75. end
  76. `ifdef DEBUG
  77. $display("round_frac: %h", round_frac);
  78. `endif
  79. end
  80. endfunction
  81. // This function calculates high_time, low_time, w_edge, and no_count
  82. // of a non-fractional counter based on the divide and duty cycle
  83. //
  84. // NOTE: high_time and low_time are returned as integers between 0 and 63
  85. // inclusive. 64 should equal 6'b000000 (in other words it is okay to
  86. // ignore the overflow)
  87. function [13:0] mmcm_divider
  88. (
  89. input [7:0] divide, // Max divide is 128
  90. input [31:0] duty_cycle // Duty cycle is multiplied by 100,000
  91. );
  92. reg [`FIXED_WIDTH:1] duty_cycle_fix;
  93. // min/max allowed duty cycle range calc for divide => 64
  94. reg [`FIXED_WIDTH:1] duty_cycle_min;
  95. reg [`FIXED_WIDTH:1] duty_cycle_max;
  96. // High/Low time is initially calculated with a wider integer to prevent a
  97. // calculation error when it overflows to 64.
  98. reg [6:0] high_time;
  99. reg [6:0] low_time;
  100. reg w_edge;
  101. reg no_count;
  102. reg [`FIXED_WIDTH:1] temp;
  103. begin
  104. // Duty Cycle must be between 0 and 1,000
  105. if(duty_cycle <=0 || duty_cycle >= 100000) begin
  106. $display("ERROR: duty_cycle: %d is invalid", duty_cycle);
  107. $finish;
  108. end
  109. if (divide >= 64) begin // DCD and frequency generation fix if O divide => 64
  110. duty_cycle_min = ((divide - 64) * 100_000) / divide;
  111. duty_cycle_max = (64.5 / divide) * 100_000;
  112. if (duty_cycle > duty_cycle_max) duty_cycle = duty_cycle_max;
  113. if (duty_cycle < duty_cycle_min) duty_cycle = duty_cycle_min;
  114. end
  115. // Convert to FIXED_WIDTH-FRAC_PRECISION.FRAC_PRECISION fixed point
  116. duty_cycle_fix = (duty_cycle << `FRAC_PRECISION) / 100_000;
  117. `ifdef DEBUG
  118. $display("duty_cycle_fix: %h", duty_cycle_fix);
  119. `endif
  120. // If the divide is 1 nothing needs to be set except the no_count bit.
  121. // Other values are dummies
  122. if(divide == 7'h01) begin
  123. high_time = 7'h01;
  124. w_edge = 1'b0;
  125. low_time = 7'h01;
  126. no_count = 1'b1;
  127. end else begin
  128. temp = round_frac(duty_cycle_fix*divide, 1);
  129. // comes from above round_frac
  130. high_time = temp[`FRAC_PRECISION+7:`FRAC_PRECISION+1];
  131. // If the duty cycle * divide rounded is .5 or greater then this bit
  132. // is set.
  133. w_edge = temp[`FRAC_PRECISION]; // comes from round_frac
  134. // If the high time comes out to 0, it needs to be set to at least 1
  135. // and w_edge set to 0
  136. if(high_time == 7'h00) begin
  137. high_time = 7'h01;
  138. w_edge = 1'b0;
  139. end
  140. if(high_time == divide) begin
  141. high_time = divide - 1;
  142. w_edge = 1'b1;
  143. end
  144. // Calculate low_time based on the divide setting and set no_count to
  145. // 0 as it is only used when divide is 1.
  146. low_time = divide - high_time;
  147. no_count = 1'b0;
  148. end
  149. // Set the return value.
  150. mmcm_divider = {w_edge,no_count,high_time[5:0],low_time[5:0]};
  151. end
  152. endfunction
  153. // This function calculates mx, delay_time, and phase_mux
  154. // of a non-fractional counter based on the divide and phase
  155. //
  156. // NOTE: The only valid value for the MX bits is 2'b00 to ensure the coarse mux
  157. // is used.
  158. function [10:0] mmcm_phase
  159. (
  160. // divide must be an integer (use fractional if not)
  161. // assumed that divide already checked to be valid
  162. input [7:0] divide, // Max divide is 128
  163. // Phase is given in degrees (-360,000 to 360,000)
  164. input signed [31:0] phase
  165. );
  166. reg [`FIXED_WIDTH:1] phase_in_cycles;
  167. reg [`FIXED_WIDTH:1] phase_fixed;
  168. reg [1:0] mx;
  169. reg [5:0] delay_time;
  170. reg [2:0] phase_mux;
  171. reg [`FIXED_WIDTH:1] temp;
  172. begin
  173. `ifdef DEBUG
  174. $display("mmcm_phase-divide:%d,phase:%d",
  175. divide, phase);
  176. `endif
  177. if ((phase < -360000) || (phase > 360000)) begin
  178. $display("ERROR: phase of $phase is not between -360000 and 360000");
  179. $finish;
  180. end
  181. // If phase is less than 0, convert it to a positive phase shift
  182. // Convert to (FIXED_WIDTH-FRAC_PRECISION).FRAC_PRECISION fixed point
  183. if(phase < 0) begin
  184. phase_fixed = ( (phase + 360000) << `FRAC_PRECISION ) / 1000;
  185. end else begin
  186. phase_fixed = ( phase << `FRAC_PRECISION ) / 1000;
  187. end
  188. // Put phase in terms of decimal number of vco clock cycles
  189. phase_in_cycles = ( phase_fixed * divide ) / 360;
  190. `ifdef DEBUG
  191. $display("phase_in_cycles: %h", phase_in_cycles);
  192. `endif
  193. temp = round_frac(phase_in_cycles, 3);
  194. // set mx to 2'b00 that the phase mux from the VCO is enabled
  195. mx = 2'b00;
  196. phase_mux = temp[`FRAC_PRECISION:`FRAC_PRECISION-2];
  197. delay_time = temp[`FRAC_PRECISION+6:`FRAC_PRECISION+1];
  198. `ifdef DEBUG
  199. $display("temp: %h", temp);
  200. `endif
  201. // Setup the return value
  202. mmcm_phase={mx, phase_mux, delay_time};
  203. end
  204. endfunction
  205. // This function takes the divide value and outputs the necessary lock values
  206. function [39:0] mmcm_lock_lookup
  207. (
  208. input [6:0] divide // Max divide is 64
  209. );
  210. reg [2559:0] lookup;
  211. begin
  212. lookup = {
  213. // This table is composed of:
  214. // LockRefDly_LockFBDly_LockCnt_LockSatHigh_UnlockCnt
  215. 40'b00110_00110_1111101000_1111101001_0000000001,
  216. 40'b00110_00110_1111101000_1111101001_0000000001,
  217. 40'b01000_01000_1111101000_1111101001_0000000001,
  218. 40'b01011_01011_1111101000_1111101001_0000000001,
  219. 40'b01110_01110_1111101000_1111101001_0000000001,
  220. 40'b10001_10001_1111101000_1111101001_0000000001,
  221. 40'b10011_10011_1111101000_1111101001_0000000001,
  222. 40'b10110_10110_1111101000_1111101001_0000000001,
  223. 40'b11001_11001_1111101000_1111101001_0000000001,
  224. 40'b11100_11100_1111101000_1111101001_0000000001,
  225. 40'b11111_11111_1110000100_1111101001_0000000001,
  226. 40'b11111_11111_1100111001_1111101001_0000000001,
  227. 40'b11111_11111_1011101110_1111101001_0000000001,
  228. 40'b11111_11111_1010111100_1111101001_0000000001,
  229. 40'b11111_11111_1010001010_1111101001_0000000001,
  230. 40'b11111_11111_1001110001_1111101001_0000000001,
  231. 40'b11111_11111_1000111111_1111101001_0000000001,
  232. 40'b11111_11111_1000100110_1111101001_0000000001,
  233. 40'b11111_11111_1000001101_1111101001_0000000001,
  234. 40'b11111_11111_0111110100_1111101001_0000000001,
  235. 40'b11111_11111_0111011011_1111101001_0000000001,
  236. 40'b11111_11111_0111000010_1111101001_0000000001,
  237. 40'b11111_11111_0110101001_1111101001_0000000001,
  238. 40'b11111_11111_0110010000_1111101001_0000000001,
  239. 40'b11111_11111_0110010000_1111101001_0000000001,
  240. 40'b11111_11111_0101110111_1111101001_0000000001,
  241. 40'b11111_11111_0101011110_1111101001_0000000001,
  242. 40'b11111_11111_0101011110_1111101001_0000000001,
  243. 40'b11111_11111_0101000101_1111101001_0000000001,
  244. 40'b11111_11111_0101000101_1111101001_0000000001,
  245. 40'b11111_11111_0100101100_1111101001_0000000001,
  246. 40'b11111_11111_0100101100_1111101001_0000000001,
  247. 40'b11111_11111_0100101100_1111101001_0000000001,
  248. 40'b11111_11111_0100010011_1111101001_0000000001,
  249. 40'b11111_11111_0100010011_1111101001_0000000001,
  250. 40'b11111_11111_0100010011_1111101001_0000000001,
  251. 40'b11111_11111_0011111010_1111101001_0000000001,
  252. 40'b11111_11111_0011111010_1111101001_0000000001,
  253. 40'b11111_11111_0011111010_1111101001_0000000001,
  254. 40'b11111_11111_0011111010_1111101001_0000000001,
  255. 40'b11111_11111_0011111010_1111101001_0000000001,
  256. 40'b11111_11111_0011111010_1111101001_0000000001,
  257. 40'b11111_11111_0011111010_1111101001_0000000001,
  258. 40'b11111_11111_0011111010_1111101001_0000000001,
  259. 40'b11111_11111_0011111010_1111101001_0000000001,
  260. 40'b11111_11111_0011111010_1111101001_0000000001,
  261. 40'b11111_11111_0011111010_1111101001_0000000001,
  262. 40'b11111_11111_0011111010_1111101001_0000000001,
  263. 40'b11111_11111_0011111010_1111101001_0000000001,
  264. 40'b11111_11111_0011111010_1111101001_0000000001,
  265. 40'b11111_11111_0011111010_1111101001_0000000001,
  266. 40'b11111_11111_0011111010_1111101001_0000000001,
  267. 40'b11111_11111_0011111010_1111101001_0000000001,
  268. 40'b11111_11111_0011111010_1111101001_0000000001,
  269. 40'b11111_11111_0011111010_1111101001_0000000001,
  270. 40'b11111_11111_0011111010_1111101001_0000000001,
  271. 40'b11111_11111_0011111010_1111101001_0000000001,
  272. 40'b11111_11111_0011111010_1111101001_0000000001,
  273. 40'b11111_11111_0011111010_1111101001_0000000001,
  274. 40'b11111_11111_0011111010_1111101001_0000000001,
  275. 40'b11111_11111_0011111010_1111101001_0000000001,
  276. 40'b11111_11111_0011111010_1111101001_0000000001,
  277. 40'b11111_11111_0011111010_1111101001_0000000001,
  278. 40'b11111_11111_0011111010_1111101001_0000000001
  279. };
  280. // Set lookup_entry with the explicit bits from lookup with a part select
  281. mmcm_lock_lookup = lookup[ ((64-divide)*40) +: 40];
  282. `ifdef DEBUG
  283. $display("lock_lookup: %b", mmcm_lock_lookup);
  284. `endif
  285. end
  286. endfunction
  287. // This function takes the divide value and the bandwidth setting of the MMCM
  288. // and outputs the digital filter settings necessary.
  289. function [9:0] mmcm_filter_lookup
  290. (
  291. input [6:0] divide, // Max divide is 64
  292. input [8*9:0] BANDWIDTH
  293. );
  294. reg [639:0] lookup_low;
  295. reg [639:0] lookup_low_ss;
  296. reg [639:0] lookup_high;
  297. reg [639:0] lookup_optimized;
  298. reg [9:0] lookup_entry;
  299. begin
  300. lookup_low = {
  301. // CP_RES_LFHF
  302. 10'b0010_1111_00, // 1
  303. 10'b0010_1111_00, // 2
  304. 10'b0010_1111_00, // 3
  305. 10'b0010_1111_00, // 4
  306. 10'b0010_0111_00, // ....
  307. 10'b0010_1011_00,
  308. 10'b0010_1101_00,
  309. 10'b0010_0011_00,
  310. 10'b0010_0101_00,
  311. 10'b0010_0101_00,
  312. 10'b0010_1001_00,
  313. 10'b0010_1110_00,
  314. 10'b0010_1110_00,
  315. 10'b0010_1110_00,
  316. 10'b0010_1110_00,
  317. 10'b0010_0001_00,
  318. 10'b0010_0001_00,
  319. 10'b0010_0001_00,
  320. 10'b0010_0110_00,
  321. 10'b0010_0110_00,
  322. 10'b0010_0110_00,
  323. 10'b0010_0110_00,
  324. 10'b0010_0110_00,
  325. 10'b0010_0110_00,
  326. 10'b0010_0110_00,
  327. 10'b0010_1010_00,
  328. 10'b0010_1010_00,
  329. 10'b0010_1010_00,
  330. 10'b0010_1010_00,
  331. 10'b0010_1010_00,
  332. 10'b0010_1100_00,
  333. 10'b0010_1100_00,
  334. 10'b0010_1100_00,
  335. 10'b0010_1100_00,
  336. 10'b0010_1100_00,
  337. 10'b0010_1100_00,
  338. 10'b0010_1100_00,
  339. 10'b0010_1100_00,
  340. 10'b0010_1100_00,
  341. 10'b0010_1100_00,
  342. 10'b0010_1100_00,
  343. 10'b0010_1100_00,
  344. 10'b0010_1100_00,
  345. 10'b0010_1100_00,
  346. 10'b0010_1100_00,
  347. 10'b0010_1100_00,
  348. 10'b0010_1100_00,
  349. 10'b0010_0010_00,
  350. 10'b0010_0010_00,
  351. 10'b0010_0010_00,
  352. 10'b0010_0010_00,
  353. 10'b0010_0010_00,
  354. 10'b0010_0010_00,
  355. 10'b0010_0010_00,
  356. 10'b0010_0010_00,
  357. 10'b0010_0010_00,
  358. 10'b0010_0010_00,
  359. 10'b0010_0010_00,
  360. 10'b0010_0010_00,
  361. 10'b0010_0010_00, // ....
  362. 10'b0010_0010_00, // 61
  363. 10'b0010_0010_00, // 62
  364. 10'b0010_0010_00, // 63
  365. 10'b0010_0010_00 // 64
  366. };
  367. lookup_low_ss = {
  368. // CP_RES_LFHF
  369. 10'b0010_1111_11, // 1
  370. 10'b0010_1111_11, // 2
  371. 10'b0010_1111_11, // 3
  372. 10'b0010_1111_11, // 4
  373. 10'b0010_0111_11, // ....
  374. 10'b0010_1011_11,
  375. 10'b0010_1101_11,
  376. 10'b0010_0011_11,
  377. 10'b0010_0101_11,
  378. 10'b0010_0101_11,
  379. 10'b0010_1001_11,
  380. 10'b0010_1110_11,
  381. 10'b0010_1110_11,
  382. 10'b0010_1110_11,
  383. 10'b0010_1110_11,
  384. 10'b0010_0001_11,
  385. 10'b0010_0001_11,
  386. 10'b0010_0001_11,
  387. 10'b0010_0110_11,
  388. 10'b0010_0110_11,
  389. 10'b0010_0110_11,
  390. 10'b0010_0110_11,
  391. 10'b0010_0110_11,
  392. 10'b0010_0110_11,
  393. 10'b0010_0110_11,
  394. 10'b0010_1010_11,
  395. 10'b0010_1010_11,
  396. 10'b0010_1010_11,
  397. 10'b0010_1010_11,
  398. 10'b0010_1010_11,
  399. 10'b0010_1100_11,
  400. 10'b0010_1100_11,
  401. 10'b0010_1100_11,
  402. 10'b0010_1100_11,
  403. 10'b0010_1100_11,
  404. 10'b0010_1100_11,
  405. 10'b0010_1100_11,
  406. 10'b0010_1100_11,
  407. 10'b0010_1100_11,
  408. 10'b0010_1100_11,
  409. 10'b0010_1100_11,
  410. 10'b0010_1100_11,
  411. 10'b0010_1100_11,
  412. 10'b0010_1100_11,
  413. 10'b0010_1100_11,
  414. 10'b0010_1100_11,
  415. 10'b0010_1100_11,
  416. 10'b0010_0010_11,
  417. 10'b0010_0010_11,
  418. 10'b0010_0010_11,
  419. 10'b0010_0010_11,
  420. 10'b0010_0010_11,
  421. 10'b0010_0010_11,
  422. 10'b0010_0010_11,
  423. 10'b0010_0010_11,
  424. 10'b0010_0010_11,
  425. 10'b0010_0010_11,
  426. 10'b0010_0010_11,
  427. 10'b0010_0010_11,
  428. 10'b0010_0010_11, // ....
  429. 10'b0010_0010_11, // 61
  430. 10'b0010_0010_11, // 62
  431. 10'b0010_0010_11, // 63
  432. 10'b0010_0010_11 // 64
  433. };
  434. lookup_high = {
  435. // CP_RES_LFHF
  436. 10'b0010_1111_00, // 1
  437. 10'b0100_1111_00, // 2
  438. 10'b0101_1011_00, // 3
  439. 10'b0111_0111_00, // 4
  440. 10'b1101_0111_00, // ....
  441. 10'b1110_1011_00,
  442. 10'b1110_1101_00,
  443. 10'b1111_0011_00,
  444. 10'b1110_0101_00,
  445. 10'b1111_0101_00,
  446. 10'b1111_1001_00,
  447. 10'b1101_0001_00,
  448. 10'b1111_1001_00,
  449. 10'b1111_1001_00,
  450. 10'b1111_1001_00,
  451. 10'b1111_1001_00,
  452. 10'b1111_0101_00,
  453. 10'b1111_0101_00,
  454. 10'b1100_0001_00,
  455. 10'b1100_0001_00,
  456. 10'b1100_0001_00,
  457. 10'b0101_1100_00,
  458. 10'b0101_1100_00,
  459. 10'b0101_1100_00,
  460. 10'b0101_1100_00,
  461. 10'b0011_0100_00,
  462. 10'b0011_0100_00,
  463. 10'b0011_0100_00,
  464. 10'b0011_0100_00,
  465. 10'b0011_0100_00,
  466. 10'b0011_0100_00,
  467. 10'b0011_0100_00,
  468. 10'b0011_0100_00,
  469. 10'b0011_0100_00,
  470. 10'b0011_0100_00,
  471. 10'b0011_0100_00,
  472. 10'b0011_0100_00,
  473. 10'b0011_0100_00,
  474. 10'b0011_0100_00,
  475. 10'b0011_0100_00,
  476. 10'b0011_0100_00,
  477. 10'b0010_1000_00,
  478. 10'b0010_1000_00,
  479. 10'b0010_1000_00,
  480. 10'b0010_1000_00,
  481. 10'b0010_1000_00,
  482. 10'b0111_0001_00,
  483. 10'b0111_0001_00,
  484. 10'b0100_1100_00,
  485. 10'b0100_1100_00,
  486. 10'b0100_1100_00,
  487. 10'b0100_1100_00,
  488. 10'b0110_0001_00,
  489. 10'b0110_0001_00,
  490. 10'b0101_0110_00,
  491. 10'b0101_0110_00,
  492. 10'b0101_0110_00,
  493. 10'b0010_0100_00,
  494. 10'b0010_0100_00,
  495. 10'b0010_0100_00, // ....
  496. 10'b0010_0100_00, // 61
  497. 10'b0100_1010_00, // 62
  498. 10'b0011_1100_00, // 63
  499. 10'b0011_1100_00 // 64
  500. };
  501. lookup_optimized = {
  502. // CP_RES_LFHF
  503. 10'b0010_1111_00, // 1
  504. 10'b0100_1111_00, // 2
  505. 10'b0101_1011_00, // 3
  506. 10'b0111_0111_00, // 4
  507. 10'b1101_0111_00, // ....
  508. 10'b1110_1011_00,
  509. 10'b1110_1101_00,
  510. 10'b1111_0011_00,
  511. 10'b1110_0101_00,
  512. 10'b1111_0101_00,
  513. 10'b1111_1001_00,
  514. 10'b1101_0001_00,
  515. 10'b1111_1001_00,
  516. 10'b1111_1001_00,
  517. 10'b1111_1001_00,
  518. 10'b1111_1001_00,
  519. 10'b1111_0101_00,
  520. 10'b1111_0101_00,
  521. 10'b1100_0001_00,
  522. 10'b1100_0001_00,
  523. 10'b1100_0001_00,
  524. 10'b0101_1100_00,
  525. 10'b0101_1100_00,
  526. 10'b0101_1100_00,
  527. 10'b0101_1100_00,
  528. 10'b0011_0100_00,
  529. 10'b0011_0100_00,
  530. 10'b0011_0100_00,
  531. 10'b0011_0100_00,
  532. 10'b0011_0100_00,
  533. 10'b0011_0100_00,
  534. 10'b0011_0100_00,
  535. 10'b0011_0100_00,
  536. 10'b0011_0100_00,
  537. 10'b0011_0100_00,
  538. 10'b0011_0100_00,
  539. 10'b0011_0100_00,
  540. 10'b0011_0100_00,
  541. 10'b0011_0100_00,
  542. 10'b0011_0100_00,
  543. 10'b0011_0100_00,
  544. 10'b0010_1000_00,
  545. 10'b0010_1000_00,
  546. 10'b0010_1000_00,
  547. 10'b0010_1000_00,
  548. 10'b0010_1000_00,
  549. 10'b0111_0001_00,
  550. 10'b0111_0001_00,
  551. 10'b0100_1100_00,
  552. 10'b0100_1100_00,
  553. 10'b0100_1100_00,
  554. 10'b0100_1100_00,
  555. 10'b0110_0001_00,
  556. 10'b0110_0001_00,
  557. 10'b0101_0110_00,
  558. 10'b0101_0110_00,
  559. 10'b0101_0110_00,
  560. 10'b0010_0100_00,
  561. 10'b0010_0100_00,
  562. 10'b0010_0100_00, // ....
  563. 10'b0010_0100_00, // 61
  564. 10'b0100_1010_00, // 62
  565. 10'b0011_1100_00, // 63
  566. 10'b0011_1100_00 // 64
  567. };
  568. // Set lookup_entry with the explicit bits from lookup with a part select
  569. if(BANDWIDTH == "LOW") begin
  570. // Low Bandwidth
  571. mmcm_filter_lookup = lookup_low[((64-divide)*10) +: 10];
  572. end
  573. else if (BANDWIDTH == "LOW_SS") begin
  574. // low Spread spectrum bandwidth
  575. mmcm_filter_lookup = lookup_low_ss[((64-divide)*10) +: 10];
  576. end
  577. else if (BANDWIDTH == "HIGH") begin
  578. // High bandwidth
  579. mmcm_filter_lookup = lookup_high[((64-divide)*10) +: 10];
  580. end
  581. else if (BANDWIDTH == "OPTIMIZED") begin
  582. // Optimized bandwidth
  583. mmcm_filter_lookup = lookup_optimized[((64-divide)*10) +: 10];
  584. end
  585. `ifdef DEBUG
  586. $display("filter_lookup: %b", mmcm_filter_lookup);
  587. `endif
  588. end
  589. endfunction
  590. // This function takes in the divide, phase, and duty cycle
  591. // setting to calculate the upper and lower counter registers.
  592. function [37:0] mmcm_count_calc
  593. (
  594. input [7:0] divide, // Max divide is 128
  595. input signed [31:0] phase,
  596. input [31:0] duty_cycle // Multiplied by 100,000
  597. );
  598. reg [13:0] div_calc;
  599. reg [16:0] phase_calc;
  600. begin
  601. `ifdef DEBUG
  602. $display("mmcm_count_calc- divide:%h, phase:%d, duty_cycle:%d",
  603. divide, phase, duty_cycle);
  604. `endif
  605. // w_edge[13], no_count[12], high_time[11:6], low_time[5:0]
  606. div_calc = mmcm_divider(divide, duty_cycle);
  607. // mx[10:9], pm[8:6], dt[5:0]
  608. phase_calc = mmcm_phase(divide, phase);
  609. // Return value is the upper and lower address of counter
  610. // Upper address is:
  611. // RESERVED [31:26]
  612. // MX [25:24]
  613. // EDGE [23]
  614. // NOCOUNT [22]
  615. // DELAY_TIME [21:16]
  616. // Lower Address is:
  617. // PHASE_MUX [15:13]
  618. // RESERVED [12]
  619. // HIGH_TIME [11:6]
  620. // LOW_TIME [5:0]
  621. `ifdef DEBUG
  622. $display("div:%d dc:%d phase:%d ht:%d lt:%d ed:%d nc:%d mx:%d dt:%d pm:%d",
  623. divide, duty_cycle, phase, div_calc[11:6], div_calc[5:0],
  624. div_calc[13], div_calc[12],
  625. phase_calc[16:15], phase_calc[5:0], phase_calc[14:12]);
  626. `endif
  627. mmcm_count_calc =
  628. {
  629. // Upper Address
  630. 6'h00, phase_calc[10:9], div_calc[13:12], phase_calc[5:0],
  631. // Lower Address
  632. phase_calc[8:6], 1'b0, div_calc[11:0]
  633. };
  634. end
  635. endfunction
  636. // This function takes in the divide, phase, and duty cycle
  637. // setting to calculate the upper and lower counter registers.
  638. // for fractional multiply/divide functions.
  639. //
  640. //
  641. function [37:0] mmcm_frac_count_calc
  642. (
  643. input [7:0] divide, // Max divide is 128
  644. input signed [31:0] phase,
  645. input [31:0] duty_cycle, // Multiplied by 1,000
  646. input [9:0] frac // Multiplied by 1000
  647. );
  648. //Required for fractional divide calculations
  649. reg [7:0] lt_frac;
  650. reg [7:0] ht_frac;
  651. reg wf_fall_frac;
  652. reg wf_rise_frac;
  653. reg [31:0] a;
  654. reg [7:0] pm_rise_frac_filtered ;
  655. reg [7:0] pm_fall_frac_filtered ;
  656. reg [7:0] clkout0_divide_int;
  657. reg [2:0] clkout0_divide_frac;
  658. reg [7:0] even_part_high;
  659. reg [7:0] even_part_low;
  660. reg [15:0] drp_reg1;
  661. reg [15:0] drp_reg2;
  662. reg [5:0] drp_regshared;
  663. reg [7:0] odd;
  664. reg [7:0] odd_and_frac;
  665. reg [7:0] pm_fall;
  666. reg [7:0] pm_rise;
  667. reg [7:0] dt;
  668. reg [7:0] dt_int;
  669. reg [63:0] dt_calc;
  670. reg [7:0] pm_rise_frac;
  671. reg [7:0] pm_fall_frac;
  672. reg [31:0] a_per_in_octets;
  673. reg [31:0] a_phase_in_cycles;
  674. parameter precision = 0.125;
  675. reg [31:0] phase_fixed; // changed to 31:0 from 32:1 jt 5/2/11
  676. reg [31:0] phase_pos;
  677. reg [31:0] phase_vco;
  678. reg [31:0] temp;// changed to 31:0 from 32:1 jt 5/2/11
  679. reg [13:0] div_calc;
  680. reg [16:0] phase_calc;
  681. begin
  682. `ifdef DEBUG
  683. $display("mmcm_frac_count_calc- divide:%h, phase:%d, duty_cycle:%d",
  684. divide, phase, duty_cycle);
  685. `endif
  686. //convert phase to fixed
  687. if ((phase < -360000) || (phase > 360000)) begin
  688. $display("ERROR: phase of $phase is not between -360000 and 360000");
  689. $finish;
  690. end
  691. // Return value is
  692. // Shared data
  693. // RESERVED [37:36]
  694. // FRAC_TIME [35:33]
  695. // FRAC_WF_FALL [32]
  696. // Register 2 - Upper address is:
  697. // RESERVED [31:26]
  698. // MX [25:24]
  699. // EDGE [23]
  700. // NOCOUNT [22]
  701. // DELAY_TIME [21:16]
  702. // Register 1 - Lower Address is:
  703. // PHASE_MUX [15:13]
  704. // RESERVED [12]
  705. // HIGH_TIME [11:6]
  706. // LOW_TIME [5:0]
  707. clkout0_divide_frac = frac / 125;
  708. clkout0_divide_int = divide;
  709. even_part_high = clkout0_divide_int >> 1;//$rtoi(clkout0_divide_int / 2);
  710. even_part_low = even_part_high;
  711. odd = clkout0_divide_int - even_part_high - even_part_low;
  712. odd_and_frac = (8*odd) + clkout0_divide_frac;
  713. lt_frac = even_part_high - (odd_and_frac <= 9);//IF(odd_and_frac>9,even_part_high, even_part_high - 1)
  714. ht_frac = even_part_low - (odd_and_frac <= 8);//IF(odd_and_frac>8,even_part_low, even_part_low- 1)
  715. pm_fall = {odd[6:0],2'b00} + {6'h00, clkout0_divide_frac[2:1]}; // using >> instead of clkout0_divide_frac / 2
  716. pm_rise = 0; //0
  717. wf_fall_frac = ((odd_and_frac >=2) && (odd_and_frac <=9)) || ((clkout0_divide_frac == 1) && (clkout0_divide_int == 2));//CRS610807
  718. wf_rise_frac = (odd_and_frac >=1) && (odd_and_frac <=8);//IF(odd_and_frac>=1,IF(odd_and_frac <= 8,1,0),0)
  719. //Calculate phase in fractional cycles
  720. a_per_in_octets = (8 * divide) + (frac / 125) ;
  721. a_phase_in_cycles = (phase+10) * a_per_in_octets / 360000 ;//Adding 1 due to rounding errors
  722. pm_rise_frac = (a_phase_in_cycles[7:0] ==8'h00)?8'h00:a_phase_in_cycles[7:0] - {a_phase_in_cycles[7:3],3'b000};
  723. dt_calc = ((phase+10) * a_per_in_octets / 8 )/360000 ;//TRUNC(phase* divide / 360); //or_simply (a_per_in_octets / 8)
  724. dt = dt_calc[7:0];
  725. pm_rise_frac_filtered = (pm_rise_frac >=8) ? (pm_rise_frac ) - 8: pm_rise_frac ; //((phase_fixed * (divide + frac / 1000)) / 360) - {pm_rise_frac[7:3],3'b000};//$rtoi(clkout0_phase * clkout0_divide / 45);//a;
  726. dt_int = dt + (& pm_rise_frac[7:4]); //IF(pm_rise_overwriting>7,dt+1,dt)
  727. pm_fall_frac = pm_fall + pm_rise_frac;
  728. pm_fall_frac_filtered = pm_fall + pm_rise_frac - {pm_fall_frac[7:3], 3'b000};
  729. div_calc = mmcm_divider(divide, duty_cycle); //Use to determine edge[7], no count[6]
  730. phase_calc = mmcm_phase(divide, phase);// returns{mx[1:0], phase_mux[2:0], delay_time[5:0]}
  731. drp_regshared[5:0] = { 2'b11, pm_fall_frac_filtered[2:0], wf_fall_frac};
  732. drp_reg2[15:0] = { 1'b0, clkout0_divide_frac[2:0], 1'b1, wf_rise_frac, 4'h0, dt[5:0] };
  733. drp_reg1[15:0] = { pm_rise_frac_filtered[2], pm_rise_frac_filtered[1], pm_rise_frac_filtered[0], 1'b0, ht_frac[5:0], lt_frac[5:0] };
  734. mmcm_frac_count_calc[37:0] = {drp_regshared, drp_reg2, drp_reg1} ;
  735. `ifdef DEBUG
  736. $display("DADDR Reg1 %h", drp_reg1);
  737. $display("DADDR Reg2 %h", drp_reg2);
  738. $display("DADDR Reg Shared %h", drp_regshared);
  739. $display("-%d.%d p%d>> :DADDR_9_15 frac30to28.frac_en.wf_r_frac.dt:%b%d%d_%b:DADDR_7_13 pm_f_frac_filtered_29to27.wf_f_frac_26:%b%d:DADDR_8_14.pm_r_frac_filt_15to13.ht_frac.lt_frac:%b%b%b:", divide, frac, phase, clkout0_divide_frac, 1, wf_rise_frac, dt, pm_fall_frac_filtered, wf_fall_frac, pm_rise_frac_filtered, ht_frac, lt_frac);
  740. `endif
  741. end
  742. endfunction