synthesisable VHDL for a fixed ratio frequency divider

http://fractional-divider.tripod.com/


1
-------------------------------------------------------------------------------- 2 -- File : fracn20.vhd 3 -- Contains : entity fracn20 (architecture rtl) 4 -- Author : Allan Herriman 5 -- Date : Tue Dec 24 2002 6 -- Version : 2.0.0 7 -- Complain to : fractional_divider@hotmail.com 8 -- License : (read below) 9 -- 10 -- This file contains synthesisable VHDL for a fixed ratio frequency divider. 11 -- 12 -- The output frequency is a rational multiple of the input 13 -- frequency in the form: 14 -- 15 -- (a + b) 16 -- ----------------------- * Fin 17 -- (a * n) + (b * (n + 1)) 18 -- 19 -- where a, b, and n are integers. 20 -- The dual modulus prescaler divides the input clock by n or (n+1). 21 -- The controller causes the prescaler to divide by n for a cycles of the 22 -- output, and divide by (n+1) for b cycles of the output. 23 -- The controller consists of a state machine that produces the best 24 -- interleaving of the a and b cycles, 25 -- which gives the minimum possible amount of jitter. 26 -- The peak to peak output jitter will be <= one period of the input clock. 27 -- 28 -- Here is a block diagram: 29 -- 30 -- +--------------+ 31 -- | Dual modulus | 'prescaler_out' 32 -- 'clock'---->| Prescaler |------+---------> 33 -- | /n or /(n+1) | | 34 -- +--------------+ | 35 -- ^ | 36 -- | +------------+ 37 -- | | | 38 -- +-------| Controller | 39 -- 'modulus_control' | | 40 -- +------------+ 41 -- 42 -- 43 -- The generics: 44 -- input_frequency - set this to the input clock frequency in Hz 45 -- output_frequency - set this to the desired output frequency in Hz 46 -- tolerance - set this to the allowable relative tolerance 47 -- on the output frequency. The default value 48 -- of 1.0e-7 should be adequate for most purposes. 49 -- VHDL guarantees only about 15 digits of precision, 50 -- so tolerances < 1e-15 don't make much sense. 51 -- Don't make tolerance exactly zero, as 52 -- floating point precision problems may cause an 53 -- infinite loop. 54 -- 55 -- Note: the output_50 output has a (nominally) 50% duty cycle. 56 -- This output will only be valid if output_frequency < 0.5 * input_frequency 57 -- 58 -- Revisions: 59 -- 2.0.0 Dec 24 2002 Initial revision. 60 -- (Starting at 2.0.0, to distinguish it from earlier VHDL-generating 61 -- Perl scripts.) 62 -- 63 -- License: 64 -- This source code (and accompanying test bench and scripts) are released 65 -- under the terms of the BSD license. 66 -- http://www.opensource.org/licenses/bsd-license.html 67 -- 68 -- Copyright (c) 2003, Allan Herriman 69 -- All rights reserved. 70 -- 71 -- Redistribution and use in source and binary forms, with or without 72 -- modification, are permitted provided that the following conditions 73 -- are met: 74 -- 75 -- Redistributions of source code must retain the above copyright 76 -- notice, this list of conditions and the following disclaimer. 77 -- Redistributions in binary form must reproduce the above copyright 78 -- notice, this list of conditions and the following disclaimer in 79 -- the documentation and/or other materials provided with the 80 -- distribution. 81 -- The name of Allan Herriman may not be used to endorse or promote 82 -- products derived from this software without specific prior 83 -- written permission. 84 -- 85 -- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 86 -- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 87 -- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 88 -- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 89 -- OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 90 -- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 91 -- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 92 -- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 93 -- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 94 -- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 95 -- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 96 -- 97 -- 98 -- 99 -- BUGS: 100 -- This code is a straightforward translation of the perl script fracn09.pl 101 -- to VHDL. Please see fracn09.pl for a list of bugs. 102 -- http://fractional_divider.tripod.com/fracn09.zip 103 -- 104 -- Simulation Status: 105 -- It should work fine in any VHDL '93 or '00 LRM compliant simulator. 106 -- Seems to work fine in recent versions of Modelsim and Simili. 107 -- It wouldn't compile in Scirocco Version 2006.6-6. 108 -- 109 -- Synthesis Status (Jan '03): 110 -- It should work find in any reasonable VHDL '93 or '00 synthesiser, 111 -- as only basic RTL code has been used. (Some tools may object to 112 -- the assert statements though. If this is the case, those statements 113 -- may be removed without changing the function of the code.) 114 -- 115 -- Seems to work fine in: 116 -- - LeonardoSpectrum 2002e build 16 (other versions may be ok, but 117 -- haven't been tested) 118 -- - Synplify Pro 7.3.0 and later 119 -- 120 -- Doesn't work in: 121 -- - Synplify Pro prior to version 7.3.0 122 -- - Any synthesis tool from Synopsys. 123 -- - Any of the low cost, FPGA vendor supplied tools (e.g. XST, MAXPLUS2). 124 -- 125 -- Common tool problems: 126 -- - Can't handle VHDL '93 syntax. 127 -- - Can't handle generics of type real. 128 -- - They think that function f_prescaler_params contains an 129 -- infinite loop. 130 -- - Fails an internal assertion. 131 -- - Incorrect calculation of "longest static prefix" of signal stageout 132 -- causing multiple drivers. 133 -- - Doesn't correctly interpret the LRM rules regarding initial values 134 -- on ports 135 -- 136 -- If your particular toolset doesn't work with this code, 137 -- please consider instead using fracn09.pl available at 138 -- http://fractional_divider.tripod.com/ 139 -------------------------------------------------------------------------------- 140 141 library ieee; 142 use ieee.std_logic_1164.all; 143 144 entity fracn20 is 145 generic ( 146 input_frequency : real; -- := 1.0e6; -- frequency of clock (Hz) 147 output_frequency : real; -- := 32768.0; -- desired frequency of output (Hz) 148 tolerance : real := 1.0e-7; 149 improve_duty_cycle : boolean := FALSE; -- TRUE uses a falling edge ff to make the output_50 duty cycle closer to 50% 150 suppress_report : boolean := TRUE 151 ); 152 port ( 153 async_reset : in std_logic := '0'; -- active high reset 154 clock : in std_logic; -- input clock 155 clock_enable : in std_logic := '1'; -- active high clock enable 156 output_50 : out std_logic; -- output - approx 50% duty cycle 157 output_pulse : out std_logic -- output - high for single clock per cycle 158 ); 159 end entity fracn20; 160 161 architecture rtl of fracn20 is 162 163 constant desired_ratio : real := (input_frequency / output_frequency); 164 constant min_ratio : real := (input_frequency / (output_frequency * (1.0 + tolerance))); 165 constant max_ratio : real := (input_frequency / (output_frequency * (1.0 - tolerance))); 166 167 pure function max (x, y : integer) return integer is 168 begin 169 if x > y then 170 return x; 171 else 172 return y; 173 end if; 174 end max; 175 176 pure function floor_to_natural (x : real) return natural is 177 variable result : natural; 178 begin 179 result := integer(x); 180 if real(result) > x then 181 result := result - 1; 182 end if; 183 return result; 184 end floor_to_natural; 185 186 pure function ceil_to_natural (x : real) return natural is 187 variable result : natural; 188 begin 189 result := integer(x); 190 if real(result) < x then 191 result := result + 1; 192 end if; 193 return result; 194 end ceil_to_natural; 195 196 -- get the integer upper and lower bounds 197 constant floor_max_ratio : positive := floor_to_natural(max_ratio); 198 constant floor_min_ratio : positive := max(floor_to_natural(min_ratio), 1); 199 constant ceil_min_ratio : positive := ceil_to_natural(min_ratio); 200 201 202 -- work out the frequency division needed in the dual modulus prescaler 203 pure function choose_n return integer is 204 variable n : positive; 205 begin 206 n := floor_min_ratio; 207 208 -- check to see if a straight integer divider will do 209 if floor_max_ratio >= ceil_min_ratio then 210 --warning("Warning: a fractional-N divider is not needed."); 211 if floor_max_ratio > ceil_min_ratio then 212 --warning(" Integer dividers $ceil_min_ratio to $floor_max_ratio are ok."); 213 n := floor_max_ratio; 214 else 215 --warning(" Integer divider $floor_max_ratio is ok."); 216 n := floor_max_ratio; 217 end if; 218 end if; 219 return n; 220 end choose_n; 221 222 -- prescaler divides by n, n+1 223 constant n : positive := choose_n; 224 225 226 type t_prescaler_params is record 227 a : natural; 228 b : natural; 229 fout_achieved : real; 230 error_achieved : real; 231 end record t_prescaler_params; 232 233 234 -- Find smallest non-negative integers a and b such that 235 -- 236 -- Fout (a + b) 237 -- ---- = ----------------------- 238 -- Fin (a * n) + (b * (n + 1)) 239 -- 240 -- (within the prescribed tolerance). 241 -- 242 -- Note: I also tried a continued PFE based on Euclid's GCD algorithm. 243 -- It used fewer iterations, but didn't always find the smallest 244 -- a and b, so was rejected. 245 pure function f_prescaler_params return t_prescaler_params is 246 variable a : natural; 247 variable b : natural; 248 variable result : t_prescaler_params; 249 variable ratio : real; 250 variable dummy_count : natural := 2_000_000_000; 251 attribute syn_looplimit : integer; -- Needed for Synplify 7.3 to work 252 attribute syn_looplimit of bigloop : label is 10_000_000; 253 begin 254 a := 1; -- number of /n cycles 255 b := 0; -- number of /(n+1) cycles 256 257 bigloop : while dummy_count > 0 loop -- test prevents spurious "infinite loop" errors from LeonardoSpectrum 258 259 ratio := real(a * n + b * (n + 1))/real(a + b); 260 261 if ratio < min_ratio then 262 -- too small 263 b := b + 1; 264 next; 265 end if; 266 if ratio > max_ratio then 267 -- too big 268 a := a + 1; 269 next; 270 end if; 271 -- just right 272 exit; 273 dummy_count := dummy_count - 1; -- never executed 274 end loop; 275 276 result.a := a; 277 result.b := b; 278 result.fout_achieved := input_frequency/ratio; -- Hz 279 result.error_achieved := result.fout_achieved - output_frequency; -- Hz 280 281 return result; 282 end f_prescaler_params; 283 284 constant prescaler_params : t_prescaler_params := f_prescaler_params; 285 286 constant relative_error : real := prescaler_params.error_achieved / output_frequency; 287 288 289 -- prescaler signals 290 signal modulus_control : std_logic; 291 signal prescaler_count : integer range 0 to n; 292 signal prescaler_out : std_logic; 293 signal prescaler_out_50 : std_logic; 294 signal duty_correction : std_logic; 295 296 297 -- controller signals and constants 298 constant max_stages : positive := 20; 299 300 type t_integer_array is array (natural range <>) of integer; 301 302 type t_stage is record 303 n : natural; -- this stage divides by n (or n+1) 304 m : natural; -- Controls duty cycle of modulus control output from this stage. 305 a : natural; -- This stage requires its modulus control input to be low for this number of cycles 306 b : natural; -- This stage requires its modulus control input to be high for this number of cycles 307 i : std_logic; -- Invert the output of this stage 308 end record t_stage; 309 310 type t_stage_array is array (natural range <>) of t_stage; 311 312 pure function f_controller_params return t_stage_array is 313 variable stage : natural := 0; 314 variable stage_array : t_stage_array(max_stages downto 0); 315 variable n1 : natural; 316 variable a1 : natural; 317 variable b1 : natural; 318 variable n2 : natural; 319 variable m2 : natural; 320 variable a2 : natural; 321 variable b2 : natural; 322 variable i2 : std_logic; 323 variable determinant : integer; 324 begin 325 stage_array(stage).n := n; 326 stage_array(stage).a := prescaler_params.a; 327 stage_array(stage).b := prescaler_params.b; 328 329 while (stage_array(stage).b > 1 and stage_array(stage).a > 1) loop 330 n1 := stage_array(stage).n; 331 a1 := stage_array(stage).a; 332 b1 := stage_array(stage).b; 333 assert n1 >= 0 and a1 >= 0 and b1 >= 0; 334 if a1 < b1 then 335 i2 := '1'; 336 n2 := (a1 + b1) / a1; 337 m2 := (a1 + b1 - 1) / a1; 338 determinant := n2 - m2 + 1; 339 assert determinant /= 0; 340 a2 := (m2 * a1 - (n2 + 1 - m2) * b1) / determinant; 341 b2 := ((1 - m2) * a1 + (n2 + 1 - m2) * b1) / determinant; 342 else 343 i2 := '0'; 344 n2 := (a1 + b1) / b1; 345 m2 := (a1 + b1 - 1)/ b1; 346 determinant := (m2 - n2 - 1); 347 assert determinant /= 0; 348 a2 := ((n2 + 1 - m2) * a1 - m2 * b1) / determinant; 349 b2 := ((m2 - n2 - 1) * a1 + (m2 - 1) * b1) / determinant; 350 end if; 351 stage := stage + 1; 352 stage_array(stage).n := n2; 353 stage_array(stage).m := m2; 354 stage_array(stage).a := a2; 355 stage_array(stage).b := b2; 356 stage_array(stage).i := i2; 357 end loop; 358 359 -- fill in the parameters for the last (non-fractional) stage 360 stage := stage + 1; 361 stage_array(stage).n := stage_array(stage - 1).a + stage_array(stage - 1).b - 1; 362 stage_array(stage).m := stage_array(stage - 1).a; 363 stage_array(stage).i := '0'; 364 365 return stage_array(stage downto 0); 366 367 end f_controller_params; 368 369 370 constant stage_array : t_stage_array := f_controller_params; 371 372 constant stages : natural := stage_array'high; 373 374 signal count : t_integer_array(stages downto 1); 375 signal carry : std_logic_vector(stages downto 0); 376 signal stageout : std_logic_vector(stages + 1 downto 1) := (others => 'W'); -- initial value works around bug in Modelsim versions prior to 5.7b 377 378 -- function to work out the modulus needed for each counter stage 379 -- (otherwise each stage will be a 32 bit counter, which 380 -- still gives the correct results, but is wasteful of logic) 381 pure function makemod(x : natural) return integer is 382 variable log : integer := 0; 383 variable my_count : integer := x; 384 begin 385 while my_count > 0 loop 386 log := log + 1; 387 my_count := my_count / 2; 388 end loop; 389 return 2 ** log; 390 end function makemod; 391 392 begin -- architecture rtl 393 394 -- print some of the constants, for debugging 395 assert suppress_report 396 report 397 "n = " & integer'image(n) & 398 " a = " & integer'image(prescaler_params.a) & 399 " b = " & integer'image(prescaler_params.b) & 400 " fout_achieved = " & real'image(prescaler_params.fout_achieved) & 401 " error_achieved = " & real'image(prescaler_params.error_achieved) & " (Hz) " & 402 real'image(relative_error) & " (rel)" & 403 " stages = " & integer'image(stages) 404 severity note; 405 406 407 -- check some of the constants 408 assert input_frequency > 0.0 severity failure; 409 assert output_frequency > 0.0 severity failure; 410 assert input_frequency >= output_frequency severity failure; 411 assert tolerance < 1.0 and tolerance >= 0.0 severity failure; 412 413 assert abs(relative_error) <= tolerance report "out of tolerance" severity error; 414 415 416 -------------------------------------------------------------------------------- 417 -- Prescaler. Divides by either n or n + 1 418 -- depending on whether the signal "modulus_control" is '0' or '1'. 419 -- Note: the "terminal count" is fixed, and the load value is 420 -- varied, to give smaller, faster logic (?) 421 -------------------------------------------------------------------------------- 422 prescaler : process (async_reset, clock) 423 begin 424 if async_reset = '1' then 425 prescaler_count <= 0; 426 prescaler_out_50 <= '0'; 427 elsif rising_edge(clock) then 428 if clock_enable = '1' then 429 -- manage counter 430 if prescaler_count < n then 431 prescaler_count <= prescaler_count + 1; 432 else 433 if modulus_control = '0' then 434 prescaler_count <= 1; 435 else 436 prescaler_count <= 0; 437 end if; 438 end if; 439 -- decode counter 440 if prescaler_count <= n/2 then 441 prescaler_out_50 <= '0'; 442 else 443 prescaler_out_50 <= '1'; 444 end if; 445 end if; 446 end if; 447 end process prescaler; 448 449 decode_prescaler_out : if n > 1 generate 450 decoder : process (async_reset, clock) 451 begin 452 if async_reset = '1' then 453 prescaler_out <= '0'; 454 elsif rising_edge(clock) then 455 if clock_enable = '1' then 456 if prescaler_count < n then 457 prescaler_out <= '0'; 458 else 459 prescaler_out <= '1'; 460 end if; 461 end if; 462 end if; 463 end process decoder; 464 end generate decode_prescaler_out; 465 466 no_decode_prescaler_out : if n <= 1 generate 467 prescaler_out <= '0' when prescaler_count = 0 else '1'; 468 end generate no_decode_prescaler_out; 469 470 output_pulse <= prescaler_out; 471 472 473 -------------------------------------------------------------------------------- 474 -- Duty cycle improvement using falling edge flip flop. 475 -------------------------------------------------------------------------------- 476 duty_cycle_improver : if improve_duty_cycle generate 477 improver : process (async_reset, clock) 478 begin 479 if async_reset = '1' then 480 duty_correction <= '0'; 481 elsif falling_edge(clock) then 482 if clock_enable = '1' then 483 duty_correction <= prescaler_out_50 and modulus_control; 484 end if; 485 end if; 486 end process improver; 487 488 output_50 <= duty_correction or prescaler_out_50; 489 490 end generate duty_cycle_improver; 491 492 no_duty_cycle_improver : if not improve_duty_cycle generate 493 output_50 <= prescaler_out_50; 494 end generate no_duty_cycle_improver; 495 496 -- trash output_50 when it will not be useful 497 trash_output_50 : if input_frequency <= 2.0 * output_frequency generate 498 output_50 <= 'X'; 499 end generate trash_output_50; 500 501 502 -------------------------------------------------------------------------------- 503 -- recursive controller 504 -- The modulus control signal for the prescaler can be generated by another 505 -- fractional-N divider, which in turn can have its modulus control signal 506 -- generated by yet another fractional-N divider, and so on. 507 -- We stop when we don't need another fractional-N divider, and can just use 508 -- a fixed divider. 509 -- The particular arrangement we use also produces the smallest possible jitter. 510 -- The stagecount and stageout signals have been initialised to non-zero 511 -- values to improve the jitter measurements during simulation. This is not 512 -- needed for synthesis, and these values should be set to zero if this 513 -- improves synthesis results. 514 -- 515 -- count will increment between 0 and stage_array(stage).n or 516 -- 1 and stage_array(stage).n, depending on output of the next stage. 517 -------------------------------------------------------------------------------- 518 controllers : for stage in 1 to stages generate 519 constant countmask : natural := makemod(stage_array(stage).n); 520 begin 521 controller : process (async_reset, clock) 522 begin 523 if async_reset = '1' then 524 count(stage) <= stage_array(stage).n; 525 carry(stage) <= '0'; 526 stageout(stage) <= stage_array(stage).i; 527 elsif rising_edge(clock) then 528 if clock_enable = '1' then 529 if carry(stage - 1) = '1' then 530 if count(stage) < stage_array(stage).n then 531 count(stage) <= (count(stage) + 1) mod countmask; 532 carry(stage) <= '0'; 533 else 534 if stageout(stage + 1) = '0' then 535 count(stage) <= 1; 536 else 537 count(stage) <= 0; 538 end if; 539 carry(stage) <= '1'; 540 end if; 541 if count(stage) < stage_array(stage).m then 542 stageout(stage) <= stage_array(stage).i; 543 else 544 stageout(stage) <= not stage_array(stage).i; 545 end if; 546 else 547 carry(stage) <= '0'; 548 end if; 549 end if; 550 end if; 551 end process controller; 552 end generate controllers; 553 554 modulus_control <= stageout(1); 555 556 carry(0) <= prescaler_out; 557 558 stageout(stages + 1) <= '1'; -- last stage is a fixed modulus divider 559 560 end architecture rtl; -- of entity fracn20 561 -------------------------------------------------------------------------------- 562 -- <EOF> fracn20.vhd 563 --------------------------------------------------------------------------------

 

posted @ 2012-05-10 19:22  IAmAProgrammer  阅读(1417)  评论(0编辑  收藏  举报