FPGARelated.com
Forums

Is this phase accumulator trick well-known???

Started by Jonathan Bromley February 8, 2009
On Feb 9, 6:19=A0pm, Brian Drummond <brian_drumm...@btconnect.com>
wrote:
> On Sun, 08 Feb 2009 21:32:40 +0000, Jonathan Bromley > > <jonathan.brom...@MYCOMPANY.com> wrote: > >On Sun, 8 Feb 2009 10:27:08 -0800 (PST), Antti wrote: > > >>ok, now i KNOW too > >>used Jons unmodifed code :) > > >It simulates correctly too, although of course it needs to > >be wrapped in something that provides a signal to connect > >to its unconstrained input port. =A0I haven't tried it with > >ISIM just yet, but I believe the code is strictly VHDL-93 > >compliant and therefore it is NOT MY FAULT if some simulator > >cannot handle it. =A0 > > Well ISIM certainly has trouble with a few VHDL constructs, so I was curi=
ous
> enough to try and find the problem here. I feel Xilinx sincerely want to =
make it
> work properly, so at one point I had 8 Webcases open, most of them report=
ing
> ISIM defects. Even 10.1.03 is significantly better than 10.1.01. > > Taking the heavy hints to build a wrapper entity, I let ISE do its "new s=
ource
> ... VHDL Module" thing (and what exactly is a VHDL Module?), added a dire=
ct
> entity instantiation, and stole Antti's intermediate signal from>i constr=
ained the signal connected to rate in the wrapper as:
> >signal rate : unsigned(15 downto 0) :=3D X"2580"; > > and tried synthesis... > > ERROR:HDLParsers:800 - "/home/brian/projects/play/baudrate/baudgen.vhd" L=
ine 50.
> =A0 =A0 =A0 =A0 Type of rate is incompatible with type of rate. > > That was easily fixed... > library IEEE; > use IEEE.STD_LOGIC_1164.ALL; > --use IEEE.STD_LOGIC_ARITH.ALL; > --use IEEE.STD_LOGIC_UNSIGNED.ALL; > use ieee.numeric_std.all; > ... but grrrrrrr.... > then synthesis was as expected. > > To try ISIM... > 1) "New Source - VHDL Testbench" and associate the DUT with the wrapper e=
ntity.
> 2) I made three trivial changes to the testbench ... > (a) comment out "USE ieee.std_logic_unsigned.all;" > (oddly enough, numeric_std was already there!) > (b) set the clock frequency > =A0 =A0 constant clock_period : time :=3D 20ns; -- was 1 us > (c) change the startup delay > =A0 =A0 wait for 100ns; -- was 100ms > This would have made more difference if I had remembered to drive the Res=
et
> signal, but never mind... > > ISIM reported > ERROR:HDLCompiler:69 - "baudgen.vhd" Line 47. rate_gen is not declared > > at which point I changed the instantiation of Jonathan's entity in my wra=
pper,
> to specify the "work" library. > Gen: entity rate_gen > to > Gen: entity work.rate_gen > > and ISIM simply worked. > > I don't know if this (requirement to specify the "work" library) is an IS=
IM
> defect, but I think it's a lesser problem than the rest of ISE, including=
XST,
> has with VHDL libraries - ignoring them altogether. > > Which means you can use components with the same name in different librar=
ies,
> and the simulator (ISIM included) will pick the one you specify, but XST =
will
> simply pick whichever it feels like, ignoring your library/use/embedded > configurations. (That's supposed to be fixed in ISE11. We'll see) > > ISIM still has problems though: > (1) the wave viewer won't show a 20ns pulse on a 1ms window, though the "=
find
> next edge" button and zooming in shows they are really there... > > (2) Increasing the baud rate > signal rate : unsigned(15 downto 0) :=3D X"25800"; > ISIM spotted the deliberate mistake and an error message flashed past, > but then it ran the out of date sim anyway (which is a VERY bad design de=
cision
> IMO) > > But fixing the mistake > signal rate : unsigned(19 downto 0) :=3D X"25800"; > and simulating for 100us, all was well. > > Antti, did you have a different problem? > > - Brian
Yes Brian little different: the wrapper: -- this works for ISIM and XST use IEEE.STD_LOGIC_1164.ALL; --use IEEE.STD_LOGIC_ARITH.ALL; --use IEEE.STD_LOGIC_UNSIGNED.ALL; use ieee.numeric_std.all; -- this works for XST but not ISIM use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; So i did MINIMAL fix to get pass XST that was not enough to pass with ISIM so the original code can pass XST/ISIM with fully proper wrapper :) nice excercise Antti
On Mon, 9 Feb 2009 08:52:59 -0800 (PST), Antti <Antti.Lukats@googlemail.com>
wrote:

>On Feb 9, 6:19&#4294967295;pm, Brian Drummond <brian_drumm...@btconnect.com> >wrote:
>> Well ISIM certainly has trouble with a few VHDL constructs, so I was curious >> enough to try and find the problem here.
[synth]
>> ERROR:HDLParsers:800 - "/home/brian/projects/play/baudrate/baudgen.vhd" Line 50. >> &#4294967295; &#4294967295; &#4294967295; &#4294967295; Type of rate is incompatible with type of rate.
[sim]
>> and ISIM simply worked.
>> Antti, did you have a different problem? >> >> - Brian > >Yes Brian little different: > >the wrapper:
>-- this works for XST but not ISIM >use IEEE.STD_LOGIC_1164.ALL; >use IEEE.STD_LOGIC_ARITH.ALL; >use IEEE.STD_LOGIC_UNSIGNED.ALL; > >So i did MINIMAL fix to get pass XST >that was not enough to pass with ISIM
Interesting because that's exactly the conditions that gave me the XST above ... type mismatch between IEEE.STD_LOGIC_UNSIGNED (in the wrapper) and numeric_std (in Jonathan's code). So I don't see how you got it through XST...
> >so the original code can pass XST/ISIM >with fully proper wrapper :) > >nice excercise
and ISIM is (somewhat) redeemed. Modelsim is clearly better. But ISIM is: cross-platform (I use it on Linux) cross-language (there is ONE model I need, only available in Verilog) supporting SmartModel (unlike Modelsim XE at all, or PE + extra cost) and a lot less than $30k - Brian
On Mon, 9 Feb 2009 08:41:39 -0800 (PST), kennheinrich@sympatico.ca wrote:

>On Feb 9, 11:19&#4294967295;am, Brian Drummond <brian_drumm...@btconnect.com> >wrote:
>> ISIM reported >> ERROR:HDLCompiler:69 - "baudgen.vhd" Line 47. rate_gen is not declared >> at which point I changed the instantiation of Jonathan's entity in my wrapper, >> to specify the "work" library. >> Gen: entity rate_gen >> to >> Gen: entity work.rate_gen >> >> and ISIM simply worked. >> >> I don't know if this (requirement to specify the "work" library) is an ISIM >> defect, but I think it's a lesser problem than the rest of ISE, including XST, >> has with VHDL libraries - ignoring them altogether. >> > >I believe that the requirement to use the "work" prefix is a >consequence of the name visibility rules in VHDL. The reason you can >usually get away with a non-prefixed simple component instance (as >opposed to an entity) is that you've already made the name visible by >"use.some_component_pkg.all". (UNISIM, VSIM, etc), or else explicitly >defined your component with the rest of your declarations.
Which ISIM also appears to handle correctly.
> A "use work.all" should achieve the same end.
And in ISIM it does. At which point I believe that
>> Gen: entity rate_gen
(without your use clause) should have failed in ISE too, at least until 11.1 comes out. (I see 11.1 "breaking" many existing projects; or at least pointing out they were already broken...) - Brian
On Feb 9, 8:07=A0pm, Brian Drummond <brian_drumm...@btconnect.com>
wrote:
> On Mon, 9 Feb 2009 08:52:59 -0800 (PST), Antti <Antti.Luk...@googlemail.c=
om>
> wrote: > > > > > > >On Feb 9, 6:19=A0pm, Brian Drummond <brian_drumm...@btconnect.com> > >wrote: > >> Well ISIM certainly has trouble with a few VHDL constructs, so I was c=
urious
> >> enough to try and find the problem here. > [synth] > >> ERROR:HDLParsers:800 - "/home/brian/projects/play/baudrate/baudgen.vhd=
" Line 50.
> >> =A0 =A0 =A0 =A0 Type of rate is incompatible with type of rate. > [sim] > >> and ISIM simply worked. > >> Antti, did you have a different problem? > > >> - Brian > > >Yes Brian little different: > > >the wrapper: > >-- this works for XST but not ISIM > >use IEEE.STD_LOGIC_1164.ALL; > >use IEEE.STD_LOGIC_ARITH.ALL; > >use IEEE.STD_LOGIC_UNSIGNED.ALL; > > >So i did MINIMAL fix to get pass XST > >that was not enough to pass with ISIM > > Interesting because that's exactly the conditions that gave me the XST ab=
ove ...
> type mismatch between =A0IEEE.STD_LOGIC_UNSIGNED (in the wrapper) and num=
eric_std
> (in Jonathan's code). > > So I don't see how you got it through XST... > > > > >so the original code can pass XST/ISIM > >with fully proper wrapper :) > > >nice excercise > > and ISIM is (somewhat) redeemed. > > Modelsim is clearly better. > > But ISIM is: > =A0 =A0 =A0 =A0 cross-platform (I use it on Linux) > =A0 =A0 =A0 =A0 cross-language (there is ONE model I need, only available=
in Verilog)
> =A0 =A0 =A0 =A0 supporting SmartModel (unlike Modelsim XE at all, or PE +=
extra cost)
> =A0 =A0 =A0 =A0 and a lot less than $30k > > - Brian
Brian plese LOOK below, my complete wrapper. AS is it passes XST until bit file all ok. but yikes in ISIM ---------------------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; --use ieee.numeric_std.all; entity rate_gen_top is Port ( clock : in STD_LOGIC; reset : in STD_LOGIC; pulse : out STD_LOGIC); end rate_gen_top; architecture Behavioral of rate_gen_top is COMPONENT rate_gen PORT( clock : IN std_logic; reset : IN std_logic; rate : IN unsigned; -- manually fixed here, ISE bug creating template! converted unsigned to std_logic ! pulse : OUT std_logic ); END COMPONENT; signal rate : unsigned(15 downto 0) :=3D X"2580"; -- 9600 baud begin Inst_rate_gen: rate_gen PORT MAP( clock =3D> clock, reset =3D> reset, rate =3D> rate, pulse =3D> pulse); end Behavioral;
On Mon, 9 Feb 2009 10:18:27 -0800 (PST), Antti wrote:

>plese LOOK below, my complete wrapper. >AS is it passes XST until bit file all ok. >but yikes in ISIM
The wrapper (collaborative effort, you + ISE) is bad VHDL (explanation below). XST is tolerating it, but should not. ISIM is right here (along with all the other simulators).
>use IEEE.STD_LOGIC_ARITH.ALL;
OK, this use-clause provides definition of type UNSIGNED.
>architecture Behavioral of rate_gen_top is > > COMPONENT rate_gen > PORT( > clock : IN std_logic; > reset : IN std_logic; > rate : IN unsigned; > pulse : OUT std_logic > ); > END COMPONENT;
OK, so the COMPONENT has a port "rate" whose data type is "ieee.std_logic_arith.unsigned". So far, so good.
>signal rate : unsigned(15 downto 0) := X"2580"; -- 9600 baud
And this signal is of the same type. Also good.
>begin > Inst_rate_gen: rate_gen PORT MAP( > clock => clock, > reset => reset, > rate => rate,
Still good. You've wired port "rate" to signal "rate" and they both have exactly the same data type. So, what's wrong? Nothing. BUT... when you try to elaborate the design, port "rate" on the component must bind to port "rate" on the entity; the component's port is "ieee.std_logic_arith.unsigned" and the entity's is "ieee.numeric_std.unsigned". Two different data types. Not compatible. XST should have choked on it. Now, this is somewhat negligent on the part of XST, but let's see what the bug report should look like... Dear Xilinx, XST compiled my code exactly the way I wanted it. Please fix XST so that it will NOT compile my code. Yours sincerely, A. Masochist. I don't see Xilinx exactly being flooded with that kind of case; do you? :-) -- 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 21:54:45 +0000, Jonathan Bromley <jonathan.bromley@MYCOMPANY.com> wrote:


>The last line requires TWO adders, in addition to the >multiplexer created by the IF. This causes a significant >performance hit. That's what I was trying to fix. I did >it by saying...
You can add 3 numbers in the same time as 2 because the maximum carry generated at any bit position is still '1'. I.e. '1' + '1' + '1' is still '11'. OK, works for 4-input LUTs. 4 numbers will make the carry chain more complicated. I have not tried if Virtex carry chains can take advantage of this. If yes, the mux should be possible in the same block. regards, Gerhard
On Feb 8, 12:02=A0pm, Jonathan Bromley <jonathan.brom...@MYCOMPANY.com>
wrote:
> hi comp.arch.fpga, > (accidentally posted to comp.lang.vhdl > a few moments ago- sorry) > > 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. =A0That 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 > =A0 Fc * M / N > where Fc is the master clock, M is the phase delta > and N is the counter's modulus. =A0However, 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: > > =A0 on every clock pulse... > =A0 =A0 if (acc < 0) then > =A0 =A0 =A0 add :=3D acc + N; > =A0 =A0 =A0 output_pulse <=3D '1'; > =A0 =A0 else > =A0 =A0 =A0 output_pulse <=3D '0'; > =A0 =A0 end if; > =A0 =A0 acc :=3D acc - M; =A0-- 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). =A0This is of course rather > easy to do since 2M is just a left shift. =A0A few > trial synthesis runs convinced me that it will give > measurably better performance than the two-adder > version. =A0VHDL 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? =A0I 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 > =A0 -- Specify the master clock frequency as a generic. > =A0 generic ( ref_Hz: positive :=3D 50_000_000 ); > =A0 port > =A0 =A0 ( clock : in =A0std_logic > =A0 =A0 ; reset : in =A0std_logic =A0-- Synchronous reset. > =A0 =A0 ; rate =A0: in =A0unsigned =A0 -- Desired output frequency > =A0 =A0 ; pulse : out std_logic =A0-- The output pulse train > =A0 =A0 ); > end; > > architecture RTL of rate_gen is > begin > =A0 process (clock) > =A0 =A0 -- variable "count" is the accumulator > =A0 =A0 variable count: integer range -2**rate'length to ref_Hz-1 :=3D 0; > =A0 =A0 -- variable "overflow" is the output pulse and wraparound marker > =A0 =A0 variable overflow: std_logic :=3D '0'; > =A0 begin > =A0 =A0 if rising_edge(clock) then > =A0 =A0 =A0 if reset =3D '1' then > =A0 =A0 =A0 =A0 count :=3D 0; > =A0 =A0 =A0 =A0 overflow :=3D '0'; > =A0 =A0 =A0 elsif count < 0 then > =A0 =A0 =A0 =A0 overflow :=3D '1'; > =A0 =A0 =A0 =A0 count :=3D count + ref_Hz; > =A0 =A0 =A0 elsif overflow =3D '1' then > =A0 =A0 =A0 =A0 overflow :=3D '0'; > =A0 =A0 =A0 =A0 count :=3D count - (to_integer(rate) * 2); > =A0 =A0 =A0 else > =A0 =A0 =A0 =A0 overflow :=3D '0'; > =A0 =A0 =A0 =A0 count :=3D count - to_integer(rate); > =A0 =A0 =A0 end if; > =A0 =A0 =A0 pulse <=3D overflow; > =A0 =A0 end if; > =A0 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.brom...@MYCOMPANY.comhttp://www.MYCOMPANY.com > > The contents of this message may contain personal views which > are not the views of Doulos Ltd., unless specifically stated. > -- > 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.brom...@MYCOMPANY.comhttp://www.MYCOMPANY.com > > The contents of this message may contain personal views which > are not the views of Doulos Ltd., unless specifically stated.
Did you see this thread on comp.lang.verilog? http://groups.google.com/group/comp.lang.verilog/browse_frm/thread/7cedbaf9= bdd6f1ad?hl=3Den#
On Mon, 9 Feb 2009 10:18:27 -0800 (PST), Antti <Antti.Lukats@googlemail.com>
wrote:

>On Feb 9, 8:07&#4294967295;pm, Brian Drummond <brian_drumm...@btconnect.com> >wrote:
>> >So i did MINIMAL fix to get pass XST >> >that was not enough to pass with ISIM >> >> Interesting because that's exactly the conditions that gave me the XST above ... >> type mismatch between &#4294967295;IEEE.STD_LOGIC_UNSIGNED (in the wrapper) and numeric_std >> (in Jonathan's code). >> >> So I don't see how you got it through XST...
>Brian >plese LOOK below, my complete wrapper. >AS is it passes XST until bit file all ok.
aha! The full code reveals the secret... cunningly exploiting a bug in XST to make it handle incorrect code! Because this uses a component declaration, XST can't error out here because it has to assume you will supply a matching entity at elaboration; if it was to check the available entities it could at best conclude you hadn't written it yet, which is completely legal... if you had used an entity as I did (reducing the work even further) it would have found the error (and did). So it's at elaboration the error occurred; XST couldn't find a matching entity, never mind, it used the first entity it could find with the right name and roughly the right number of ports! (which, being the masochist I am, I reported for ISE 7.1 and 10.1, and I'm told it should be fixed in 11)
>but yikes in ISIM
Good for ISIM, this time! - Brian
On Feb 9, 3:58=A0pm, Gerhard Hoffmann <dk...@hoffmann-hochfrequenz.de>
wrote:
> On Sun, 08 Feb 2009 21:54:45 +0000, Jonathan Bromley <jonathan.brom...@MY=
COMPANY.com> wrote:
> >The last line requires TWO adders, in addition to the > >multiplexer created by the IF. =A0This causes a significant > >performance hit. =A0That's what I was trying to fix. =A0I did > >it by saying... > > You can add 3 numbers in the same time as 2 because the maximum > carry generated at any bit position is still '1'. > I.e. '1' + '1' + '1' is still '11'. > OK, works for 4-input LUTs.
Did you forget 1 + 1 + 1 + carryin =3D 100 ?
> 4 numbers will make the carry chain more complicated. > I have not tried if Virtex carry chains can take advantage of this. > If yes, the mux should be possible in the same block.
3 numbers make the carry chain more complex. I'm sure that if it were practical or even possible to add three numbers using a single 4 LUT, we would already know about it. Rick
On Feb 9, 5:14=A0am, Jonathan Bromley <jonathan.brom...@MYCOMPANY.com>
wrote:
> On Sun, 8 Feb 2009 22:42:04 -0800 (PST), rickman wrote: > >This is an interesting problem, am I understanding it correctly? > > Yes; more correctly than I did at first, I think. > > Various people have correctly pointed out that the N-M > calculation does not need to be on a timing arc, but it's > tough to convince the tools of that.
Tough, but not impossible. There is a way to tell the tools than any path through a given point has a specified timing. You need to apply this to the net which is the output of the adder of N-M.
> Other people have correctly pointed out that my trick > to convert 2 adders and a 2-in MUX into one adder and > a 3-in MUX does not save any area. =A0I did consistently > find, however, that it gave significantly better Fmax; > I'm not 100% sure I know why. =A0If we have 6-input LUTs > then my trick would be a very big win.
I agree that the timing should be close between the two examples. But adders have to be arranged in a column while the bits of a mux can be placed anywhere close and will have good timing. I expect this is the sort of design that can be helped significantly by floorplanning.
> Finally, someone pointed out that the N-M calculation > could be pipelined. =A0In FPGAs, with one FF per LUT > whether you use it or not, that turns out better than > any other form I've tried. =A0
I'm not sure what is meant by that, but certainly it will not hurt to add FFs to the output of N-M since they are virtually static for this application. By adding FFs here, you will in essence be cutting the timing path allowing the timing analyzer to see only the portions of the design that need to be fast. In fact, you can eliminate the adder altogether by having the programmed registers hold N and N-M instead of N and M. That *will* increase speed as well as reducing footprint.
> Better still, if N and M > are both constants then the tools correctly identify > that the (N-M) pipeline register is constant, and > optimize it away. =A0So my original question, and my > original "trick", become irrelevant (except in > Spartan-6, maybe???!!!) and my "best effort" is:
I don't know what higher level muxes they have in the 6 series of parts. A 6 input LUT is still not enough to support a 3 input mux and a full adder. The LUT needs 5 inputs for the mux plus one for the accumulator plus one more for the carry input to each bit.
> library ieee; > use ieee.std_logic_1164.all; > use ieee.numeric_std.all; > > entity rate_gen is > =A0 generic ( ref_Hz: positive :=3D 50_000_000 ); > =A0 port > =A0 =A0 ( clock : in =A0std_logic > =A0 =A0 ; reset : in =A0std_logic > =A0 =A0 ; rate =A0: in =A0unsigned > =A0 =A0 ; pulse : out std_logic > =A0 =A0 ); > end; > > architecture RTL of rate_gen is > > begin > =A0 process (clock) > =A0 =A0 variable count: integer range -2**rate'length to ref_Hz-1 :=3D 0; > =A0 =A0 variable wrap: natural range 0 to ref_Hz :=3D ref_Hz; > =A0 begin > =A0 =A0 if rising_edge(clock) then > =A0 =A0 =A0 pulse <=3D '0'; > =A0 =A0 =A0 if reset =3D '1' then > =A0 =A0 =A0 =A0 count :=3D 0; > =A0 =A0 =A0 elsif count < 0 then > =A0 =A0 =A0 =A0 pulse <=3D '1'; > =A0 =A0 =A0 =A0 count :=3D count + wrap; > =A0 =A0 =A0 else > =A0 =A0 =A0 =A0 count :=3D count - to_integer(rate); > =A0 =A0 =A0 end if; > =A0 =A0 =A0 wrap :=3D ref_Hz - to_integer(rate); > =A0 =A0 end if; > =A0 end process; > end; > > The synchronous reset adds a tiny amount of delay (routing???) > and is probably unnecessary. > > But there's another idea coming...
Here is your code with two setup registers. library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity rate_gen is generic ( ref_Hz: positive :=3D 50_000_000 ); port ( clock : in std_logic ; reset : in std_logic ; rate : in unsigned ; n_m : in unsigned ; pulse : out std_logic ); end; architecture RTL of rate_gen is begin process (clock) variable count: integer range -2**rate'length to ref_Hz-1 :=3D 0; begin if rising_edge(clock) then pulse <=3D '0'; if reset =3D '1' then count :=3D 0; elsif count < 0 then pulse <=3D '1'; count :=3D count + n_m; else count :=3D count - to_integer(rate); end if; end if; end process; end; Rick