J
Jonathan Bromley
Guest
hi comp.arch.fpga,
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.
I have been messing around with baud rate generators
and suchlike - creating a pulse that's active for
one clock period at some required repetition rate -
and wanted to try a phase accumulator technique
instead of a simple divider. That makes it far
easier to specify the frequency - it's simply the
phase-delta input value - and easily allows for
non-integral divide ratios, at the cost of one
master clock period of jitter.
The phase-accumulator produces pulses with a
repetition rate of
Fc * M / N
where Fc is the master clock, M is the phase delta
and N is the counter's modulus. However, to get
the huge convenience of specifying M as the required
frequency, I must make N be equal to the frequency
of Fc, and this is unlikely to be an exact power of 2.
So the phase accumulator works like this:
on every clock pulse...
if (acc < 0) then
add := acc + N;
output_pulse <= '1';
else
output_pulse <= '0';
end if;
acc := acc - M; -- unconditionally
This is fine, but it means that on the "wrap-around"
clock cycle I must add either N-M to the accumulator;
if either M or N are variable, that costs me another
adder.
Today I came up with an intriguing (to me) alternative:
on the wrap-around cycle, add N to the accumulator;
on the immediately subsequent cycle, add (-2M); on
all other cycles, add (-M). This is of course rather
easy to do since 2M is just a left shift. A few
trial synthesis runs convinced me that it will give
measurably better performance than the two-adder
version. VHDL code is appended for anyone who wants
to play.
My question is: has this trick been published anywhere?
Or is it something that "those skilled in the art"
already know about? I haven't seen it before, but that
simply means I probably haven't looked hard enough.
Thanks!
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~ rate generator using novel wrap-around technique
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity rate_gen is
-- Specify the master clock frequency as a generic.
generic ( ref_Hz: positive := 50_000_000 );
port
( clock : in std_logic
; reset : in std_logic -- Synchronous reset.
; rate : in unsigned -- Desired output frequency
; pulse : out std_logic -- The output pulse train
);
end;
architecture RTL of rate_gen is
begin
process (clock)
-- variable "count" is the accumulator
variable count: integer range -2**rate'length to ref_Hz-1 := 0;
-- variable "overflow" is the output pulse and wraparound marker
variable overflow: std_logic := '0';
begin
if rising_edge(clock) then
if reset = '1' then
count := 0;
overflow := '0';
elsif count < 0 then
overflow := '1';
count := count + ref_Hz;
elsif overflow = '1' then
overflow := '0';
count := count - (to_integer(rate) * 2);
else
overflow := '0';
count := count - to_integer(rate);
end if;
pulse <= overflow;
end if;
end process;
end;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
--
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.
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.
I have been messing around with baud rate generators
and suchlike - creating a pulse that's active for
one clock period at some required repetition rate -
and wanted to try a phase accumulator technique
instead of a simple divider. That makes it far
easier to specify the frequency - it's simply the
phase-delta input value - and easily allows for
non-integral divide ratios, at the cost of one
master clock period of jitter.
The phase-accumulator produces pulses with a
repetition rate of
Fc * M / N
where Fc is the master clock, M is the phase delta
and N is the counter's modulus. However, to get
the huge convenience of specifying M as the required
frequency, I must make N be equal to the frequency
of Fc, and this is unlikely to be an exact power of 2.
So the phase accumulator works like this:
on every clock pulse...
if (acc < 0) then
add := acc + N;
output_pulse <= '1';
else
output_pulse <= '0';
end if;
acc := acc - M; -- unconditionally
This is fine, but it means that on the "wrap-around"
clock cycle I must add either N-M to the accumulator;
if either M or N are variable, that costs me another
adder.
Today I came up with an intriguing (to me) alternative:
on the wrap-around cycle, add N to the accumulator;
on the immediately subsequent cycle, add (-2M); on
all other cycles, add (-M). This is of course rather
easy to do since 2M is just a left shift. A few
trial synthesis runs convinced me that it will give
measurably better performance than the two-adder
version. VHDL code is appended for anyone who wants
to play.
My question is: has this trick been published anywhere?
Or is it something that "those skilled in the art"
already know about? I haven't seen it before, but that
simply means I probably haven't looked hard enough.
Thanks!
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~ rate generator using novel wrap-around technique
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity rate_gen is
-- Specify the master clock frequency as a generic.
generic ( ref_Hz: positive := 50_000_000 );
port
( clock : in std_logic
; reset : in std_logic -- Synchronous reset.
; rate : in unsigned -- Desired output frequency
; pulse : out std_logic -- The output pulse train
);
end;
architecture RTL of rate_gen is
begin
process (clock)
-- variable "count" is the accumulator
variable count: integer range -2**rate'length to ref_Hz-1 := 0;
-- variable "overflow" is the output pulse and wraparound marker
variable overflow: std_logic := '0';
begin
if rising_edge(clock) then
if reset = '1' then
count := 0;
overflow := '0';
elsif count < 0 then
overflow := '1';
count := count + ref_Hz;
elsif overflow = '1' then
overflow := '0';
count := count - (to_integer(rate) * 2);
else
overflow := '0';
count := count - to_integer(rate);
end if;
pulse <= overflow;
end if;
end process;
end;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
--
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.