📄 fracn09.pl
字号:
eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}' && eval 'exec perl -S $0 $argv:q' if 0;# fracn09.pl - Perl script for designing fractional-N frequency dividers.# Both phase-accumulator and dual-modulus-prescaler designs are performed.# Also writes VHDL and Verilog files to implement the divider.# Copyright (c) Allan Herriman 1999, 2000, 2001, 2002################################################################################# Legal notices and Copying information - please see attached readme.txt file.################################################################################# Bugs:## 0. It's much easier to read the VHDL comments in the generated VHDL than here!## 1. Currently this doesn't work if the output frequency is more than half# the input frequency. (The "50%" duty cycle output makes this impossible.)# If we remove the 50% duty cycle output, then we can have dividers with# output frequencies all the way up to the input frequency.# Requesting output frequencies > one half the input frequency currently# causes the program to terminate with an error message.# *** Fixed in version 0.04. Fout/Fin Ratios > 1/2 result in the 50% duty# cycle output being disabled, and a warning message is generated.# *** Changed in version 0.07. Fout/Fin Ratios >= 1/2 now result in the 50%# duty cycle output being disabled.## 2. The phase accumulator doesn't allow the constant to be 2 ** 31 or more,# because the generated VHDL code uses an integer to hold this number# and most VHDL tools only support the minimum required range for integers.# This limits the accuracy for this type of divider.# A warning message is issued in this case, and the achieved accuracy is# listed in the output VHDL file.# *** Fixed in version 0.06. Constants >= 2**31 now are represented by a# unsigned constant (e.g. "0101010") rather than an integer.## 3. The "50%" duty cycle output has only a roughly 50% duty cycle, and the# duty cycle may vary from cycle to cycle.# This will be particularly bad for higher Fout/Fin ratios.# If use_phase_accumulator = FALSE, the duty cycle will always be >= 50%,# or <= 50%, depending on the particular divider, unless the generic# improve_duty_cycle is TRUE, in which case the duty cycle will average to 50%.# (A falling edge ff is used when improve_duty_cycle is TRUE.)# If use_phase_accumulator = TRUE, the duty cycle will average to 50% in the# long term, but it will vary above and below 50% in the short term.# ("Short term" and "long term" depend on the divider. Ratios like# Fout/Fin = 0.4 (exactly) will cause "short term" to be effectively infinite.)# The duty cycle is made to be closer to 50%# by setting the improve_duty_cycle generic, at some cost in area.# The 50% duty cycle output is not implemented for Fout/Fin ratios >= 1/2.## 4. The "shebang" line (first line in this file) may need be changed# to suit local conditions. (Only relevant if running under unix.)# Also, unix perl will not like carriage returns left at the end of lines# by DOS text editors.# *** Fixed in version 0.09 Shebang line is now portable.## 5. Sometimes, if the tolerance is very tight, the controller process# will contain a case statement with more branches than the VHDL compilers# can handle. Relax the tolerance in this case (or hand code a better# controller). The -g switch might help here, by disabling generation of# that code.## 6. The generated VHDL code is probably far from optimal for the# particular target architecture you want to use. You could# hand edit the code to improve area and/or speed.## 7. The flip flop count is only approximate. VHDL synthesisers may# replicate or remove flip flops.# The flip flop count also may not accurately reflect the area used in# the target architecture, as combinatorial logic and routing also affect# the result.# (The phase accumulator architecture is better in this respect, as the# area results are more predictable.)# The only way to accurately determine the area is to run the design through# the synthesis, place and route tools.## 8. There is no phase relationship defined between output_50 and# output_pulse. (This is more a feature than a bug, and will not be fixed,# because it is expected that only one of output_50 and output_pulse will# be used for a particular design.)## 9. If the improve_duty_cycle generic is true and Fout < 1/2 Fin,# the output_50 output is taken from combinatorial logic,# rather than directly from the output of a flip flop.# There is no chance of glitches, however, as the comb. logic consists# of a two input function, and the inputs can never change at the same time.# One input comes from a rising edge triggered flip flop, and the other comes# from a falling edge triggered flip flop.# (The backend tools might need to be told about the timing requirements.)################################################################################# Test Status:# 1. Generating the VHDL. This Perl script has been tested under NT using# Perl 5.004 and 5.005, and on HPUX using Perl 5.003.# (Watch the carriage returns when using unix Perl.)## 2. Simulating the VHDL. The TCL regression test tries many different# randomly selected ratios and measures the frequency error and jitter# achieved. So far, tens of thousands of ratios have been tried using# Modelsim PE 5.5e, SE 5.4e, PE 5.4d and# Simili 1.4 build 34, 1.5 build 17b and 2.0 build 17.# Modelsim gives spurious warnings of the form:# WARNING[5]: fracn.vhd(259): Nonresolved signal controller_count may have multiple sources.# These warnings may safely be ignored as there can only be one driver# for that signal.## 2b. Simulating the Verilog. Still undergoing testing...## 3. Synthesis of the VHDL.# Several dividers have been tried# in Synplify 6.0.0, 6.2.0, 7.0.2, with Xilinx Virtex-e as a target.# It compiled ok, and Synplify didn't give any warnings.# The RTL and technology views [Synplify produces schematics from the code]# looked ok.# Estimated speeds were well above 100MHz in all cases.## It has also been tested with the MAX+PLUS2 compiler, which didn't work# at all. This appears to be the fault of the MAX+PLUS2 compiler.# There is no plan to make the generated code work with this compiler.## 4. Routing the sythesised EDIF. This has been tried for a few different# dividers in "production designs" running at up to 166MHz.# No problems have been encountered.################################################################################# Music Disclaimer:# This script was written while listening to the following music:# The Saints, Joy Division, The Jon Spencer Blues Explosion,# My Bloody Valentine, P J Harvey, Slint, Swervedriver, The Birthday Party,# Black Flag, The Stooges ...# Version 0.09 changes were made while listening to the music of# Spencer P. Jones.################################################################################# Revision information:## 0.02 Allan H. Added VHDL code generation.## 0.03 30-11-00 Allan H.# Changed initial value of $num_bits from 1 to 0 to allow /2 phase# accumulators to only use 1 ff.## 0.04 23-12-00 Allan H.# Now allows Fin/Fout ratio to go all the way down to 1# (previously only went to 2).# The 50% duty cycle output "output" is now disabled for Fout/Fin > 1/2.## "Odd one out" processing was reintroduced to improve vcom times by# reducing the size of the case statement under certain corner cases.# This requires async sets on some ff.## 0.05 26-12-00 Allan H.# Added negative edge ff to the 50% duty cycle prescaler output to# improve the duty cycle. Borrowed from an idea by Walter Baeck.# There is a new generic "improve_duty_cycle" to enable this behaviour.## Changed controller_table array to a string for memory size reduction.# (Particularly noticable with dividers like fracn05.pl -t 1e-7 1e7 9999999)# This hurts execution time slightly, but can save hundreds of Mbytes!## 0.06 28-12-00 Allan H.# Added recursive controller## Added -g flag to inhibit generation of "low jitter" controller,# as this was causing Modelsim vcom to crash sometimes when the case# statement became excessively large. This would only happen for# certain ratios when the tolerance was very tight (1e-10).## Added -c flag to disable convergence checks.## Phase accumulator constant can now be > 32 bits.## Various code cleanups. (It's still ugly though.)## 0.07 31-12-00 Allan H.# Added "improve duty cycle" for the phase accumulator.# (This also improves jitter (for the output_50 output of the P.A. only).)# Dividers like Fout/Fin = 0.4000 still aren't perfect, as (in this case)# the duty cycle will slowly drift between 0.4 and 0.6, but there's not# much we can do about this (not using the phase accumulator might be# one workaround). Such poor ratios are quite rare, though.# Fout/Fin = 0.5000 caused a problem with code generation for the# duty cycle improver, so this ratio now results in the output_50 output# being removed. Previously this only happened for Fout/Fin ratios just# greater than 0.5000 . This does not cause a loss of functionality,# as the output_pulse output has a 50% duty cycle for this particular# ratio.## 0.08 24-2-01 Allan H.# Added -u option to use Synopsys std_logic_unsigned instead of# IEEE.numeric_std, as some users had reported that their tools# wouldn't work with numeric_std.# Also added -s option to use Synopsys std_logic_arith.## Added -x option, which is ignored. This worked around a bug in the# TCL regression test, which would sometimes have command line arguments# that were null strings, which would cause this script to give an error.# The -x option can be used in place of the null strings.## Some minor changes to the generated comments, to reflect recent changes# to the code.## 0.09 26-12-01 Allan H.# Changed default tab size to 4.## Added experimental Verilog code generation. (This may take some time to# get right - I'm a Verilog newbie.)# Currently only the recursive controller is supported in the generated# Verilog file. This may improve once I work out a reasonable equivalent# of the VHDL "generate" statement in Verilog.## Changed -f option to the base of the output filename, rather than the# entire output filename.# E.g. before: "-f file" produced a file called "file".# now: "-f file" produces a file called "file.vhd" and another# called "file.v".# There is no way to change the extensions. VHDL always uses ".vhd", and# Verilog always uses ".v".## Changed email address in generated code to fractional_divider@hotmail.com# was: allanherriman@hotmail.com - this gets too much spam, and it's too# easy to miss an important email amongst so much rubbish.## Changed "warnings" from string to array## Fixed shebang line (first line in file) to make it more portable## Added ability to indent with tabs instead of spaces.# Previously the option "-i n" would indent with n spaces, for n > 0.# Now n = 0 will indent with tabs.################################################################################# To Do:## * "Hybrid controller" which is a combination of the recursive controller# and the minimum jitter controller. The swap from recursive controller to# minimum jitter controller should be made when the size of the case# statement would be small enough (say 16 or 32).# This should result in overall savings in area at no cost in speed.## * More code cleanups. Sigh.## * Make generated code look like the FMF or OpenCores coding style (yuck).use vars qw($version);$version = "0.09";use strict;use POSIX; # need this for floor() and ceil()use Text::Tabs; # need this for expanding tabs# Error message for command line errorssub usage_exit { foreach my $message (@_) { print $message; } print "\n"; print "Fractional-N divider VHDL and Verilog code generator\n"; print "Usage: $0 [options] input_frequency output_frequency\n"; print "Options:\n"; print " -t num sets tolerance of output_frequency (default 1e-7)\n"; print " -g inhibit generation of \"low jitter\" controller\n"; print " -c inhibit convergence checking (use with caution)\n"; print " -i num sets size of code indent (default 4). Uses tabs if num is 0\n"; print " -v toggles verbose mode\n"; print " -s use std_logic_arith instead of IEEE.numeric_std (VHDL)\n"; print " -u use std_logic_unsigned instead of IEEE.numeric_std (VHDL)\n"; print " -a string sets architecture name (VHDL) (default \"rtl\")\n"; print " -e string sets entity name (VHDL) or module name (Verilog) (default \"fracn\")\n"; print " -f string sets base part of file name (defaults to entity or module name)\n"; print " VHDL file is <string>.vhd, and Verilog file is <string>.v\n"; print "Frequency arguments are in Hz\n"; print "Examples:\n"; print "$0 1000000 32768\n"; print " produces VHDL file fracn.vhd and Verilog file fracn.v which contain a divider\n"; print " which will produce a 32.768kHz output from a 1MHz input\n"; print "$0 -a arch -e ent -f file -t 1e-9 77.76e6 1.544e6\n"; print " produces VHDL file file.vhd and Verilog file file.v which contain a divider\n"; print " which will produce a 1.544MHz output from a 77.76MHz input\n"; exit 1;}use vars qw(@warnings);@warnings = (); # the collected set of warnings# warning messages come here# messages must not contain '\n'sub warning { foreach my $message (@_) { print $message . "\n"; push @warnings, ("* " . $message . "\n"); }}############### Work out the design requirements ################################ some global variables (more later...)use vars qw($tolerance $entity_name $architecture_name);use vars qw($base_name $vhdl_name $verilog_name);use vars qw($low_jitter_controller $convergence_check $tabstop $verbose);use vars qw($std_logic_arith $std_logic_unsigned);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -