FPGARelated.com
Forums

Is this phase accumulator trick well-known???

Started by Jonathan Bromley February 8, 2009
On Feb 9, 5:57=A0am, Jonathan Bromley <jonathan.brom...@MYCOMPANY.com>
wrote:
> On Mon, 09 Feb 2009 10:14:09 +0000, Jonathan Bromley wrote: > >But there's another idea coming... > > which is to time-division mux the two additions. > This degrades the jitter to 2 master clock periods, > but gives what I believe to be the most compact > and fastest possible implementation for a phase > accumulator whose modulus is not a power of 2. > I removed the reset because it's fairly useless. > > As with the earlier implementation, this one > can only provide output rates up to Fc/2. > > =A0 library ieee; > =A0 use ieee.std_logic_1164.all; > =A0 use ieee.numeric_std.all; > > =A0 entity rate_gen is > =A0 =A0 generic ( ref_Hz: positive :=3D 50_000_000 ); > =A0 =A0 port > =A0 =A0 =A0 ( clock : in =A0std_logic > =A0 =A0 =A0 ; rate =A0: in =A0unsigned > =A0 =A0 =A0 ; pulse : out std_logic > =A0 =A0 =A0 ); > =A0 end; > > =A0 architecture RTL_2ph of rate_gen is > =A0 begin > =A0 =A0 process (clock) > =A0 =A0 =A0 -- Halve the modulus to account for 2-phase operation > =A0 =A0 =A0 constant modulus: integer :=3D ref_Hz/2; > =A0 =A0 =A0 -- This flag controls the adder multiplexing > =A0 =A0 =A0 variable phase: boolean; > =A0 =A0 =A0 variable count: integer range -2**rate'length to modulus-1 :=
=3D 0;
> =A0 =A0 begin > =A0 =A0 =A0 if rising_edge(clock) then > =A0 =A0 =A0 =A0 pulse <=3D '0'; > =A0 =A0 =A0 =A0 if phase then > =A0 =A0 =A0 =A0 =A0 count :=3D count - to_integer(rate); > =A0 =A0 =A0 =A0 elsif count < 0 then > =A0 =A0 =A0 =A0 =A0 count :=3D count + modulus; > =A0 =A0 =A0 =A0 =A0 pulse <=3D '1'; > =A0 =A0 =A0 =A0 end if; > =A0 =A0 =A0 =A0 phase :=3D not phase; > =A0 =A0 =A0 end if; > =A0 =A0 end process; > > =A0 end; > > Thanks for all the comments.
I don't get how this is smaller or faster than any of the other approaches. Rick
On Mon, 9 Feb 2009 14:13:23 -0800 (PST), Gabor wrote:

>On Feb 8, 12:02&#4294967295;pm, Jonathan Bromley wrote: >> The question - repeated after the explanation - >> is: here's what I think is a nifty trick; has >> anyone seen it, or been aware of it, before? >> I can't believe it's really new.
[...]
>Did you see this thread on comp.lang.verilog?
http://groups.google.com/group/comp.lang.verilog/browse_frm/thread/7cedbaf9bdd6f1ad?hl=en# No, I don't recall reading it... looks interesting. Thanks for the pointer. -- Jonathan Bromley, Consultant DOULOS - Developing Design Know-how VHDL * Verilog * SystemC * e * Perl * Tcl/Tk * Project Services Doulos Ltd., 22 Market Place, Ringwood, BH24 1AW, UK jonathan.bromley@MYCOMPANY.com http://www.MYCOMPANY.com The contents of this message may contain personal views which are not the views of Doulos Ltd., unless specifically stated.
On Sun, 08 Feb 2009 23:23:00 GMT, Nico Coesel wrote:


>What if you simply add N-M to the accumulator? > > on every clock pulse... > if (acc < 0) then > acc := acc + (N -M); > output_pulse <= '1'; > else > output_pulse <= '0'; > acc := acc - M; > end if;
That is very good if N and M are both constants, but I wanted to deal with the case where M is a variable and in that case we end up with two adders which have to be cascaded somehow. I revisited the problem for the case where N and M are both constants, and noted that you can easily precalculate the greatest common divisor of N, M and thereby reduce the fraction M/N to its lowest terms. This helps to minimize the design without unnecessary human effort, which rates pretty highly on my lazy man's list of desiderata. Here's the code... -- put this in a package, or in the architecture entity fixed_rate_gen is generic (divisor, multiplier: positive); port (clock: in std_logic; pulse: out std_logic); end; architecture rtl of fixed_rate_gen is function euclid_gcd(divisor, multiplier: positive) return positive is variable r0, r1, r: natural; begin assert multiplier <= divisor report "Multiplier is greater than divisor" severity failure; r0 := multiplier; r1 := divisor; while r0 /= 0 loop r := r1 rem r0; r1 := r0; r0 := r; end loop; return r1; end; constant gcd: positive := euclid_gcd(divisor, multiplier); constant m: positive := multiplier/ gcd; constant wrap: positive := (divisor / gcd) - m; begin process (clock) variable acc: integer range -m to wrap-1 := 0; begin if rising_edge(clock) then if acc < 0 then acc := acc + wrap; pulse <= '1'; else acc := acc - m; pulse <= '0'; end if; end if; end process; end; I love the Euclid GCD algorithm - so neat and simple, so non-obvious (to me at least). -- Jonathan Bromley, Consultant DOULOS - Developing Design Know-how VHDL * Verilog * SystemC * e * Perl * Tcl/Tk * Project Services Doulos Ltd., 22 Market Place, Ringwood, BH24 1AW, UK jonathan.bromley@MYCOMPANY.com http://www.MYCOMPANY.com The contents of this message may contain personal views which are not the views of Doulos Ltd., unless specifically stated.
On Mon, 9 Feb 2009 16:32:44 -0800 (PST), rickman <gnuarm@gmail.com> wrote:

>> OK, works for 4-input LUTs. > >Did you forget 1 + 1 + 1 + carryin = 100 ?
Ouch, incorrectly remembered 3 to 2 counter principle. Should not write about such stuff late at night. Gerhard
Jonathan Bromley <jonathan.bromley@MYCOMPANY.com> wrote:

>On Sun, 08 Feb 2009 23:23:00 GMT, Nico Coesel wrote: > > >>What if you simply add N-M to the accumulator? >> >> on every clock pulse... >> if (acc < 0) then >> acc := acc + (N -M); >> output_pulse <= '1'; >> else >> output_pulse <= '0'; >> acc := acc - M; >> end if; > >That is very good if N and M are both constants, >but I wanted to deal with the case where M is >a variable and in that case we end up with two >adders which have to be cascaded somehow.
You don't have to. Just say A=N-M and add A to the pulse accumulator. A can be calculated in a seperate process. -- Failure does not prove something is impossible, failure simply indicates you are not using the right tools... "If it doesn't fit, use a bigger hammer!" --------------------------------------------------------------
On Tue, 10 Feb 2009 17:13:07 GMT, Nico Coesel wrote:


>>...I wanted to deal with the case where M is >>a variable and in that case we end up with two >>adders which have to be cascaded somehow. > >You don't have to. Just say A=N-M and add A to the pulse accumulator. >A can be calculated in a seperate process.
Indeed it can, but in what way is that different from "cascaded somehow"? As I and others have already pointed out, you can pipeline the N-M addition at zero cost in an FPGA; but you still need two adders. -- Jonathan Bromley, Consultant DOULOS - Developing Design Know-how VHDL * Verilog * SystemC * e * Perl * Tcl/Tk * Project Services Doulos Ltd., 22 Market Place, Ringwood, BH24 1AW, UK jonathan.bromley@MYCOMPANY.com http://www.MYCOMPANY.com The contents of this message may contain personal views which are not the views of Doulos Ltd., unless specifically stated.