I'm working in a Spartan 3 with XST 10.1. I'm trying to divide down a 32 MHz clock to make a 128 kHz clock on the DCLK output pin. I'm implementing it with a downcounter that (resets itself and toggles the pin) when it gets to zero. Nothing tricky there so far. Then I synthesize the whole thing and, just for fun, go spelunking in the FPGA editor to see how it built the logic. As expected, it's a 7 bit downcounter, implemented using the carry chain. And yet the zero-detection logic, rather than using the perfectly good carry-out signal from the decrement chain, is being implemented with an 8 input NOR, split across several slices. Of course, this still works. At 32 MHz I could ship each individual bit to Taiwan on a barge and wait for the answer by carrier pidgeon and it would still work. But it seems like an odd choice to have made. By my guesstimations it's both larger and slower than using the carry-out. Anyone care to speculate why? -- Rob ---------------------------------------------------------------------- MAKE_DC_DC: process(clk) variable toggle : std_logic := '0'; constant TICKS_CYC : integer := 32_000_000 / 128_000; constant TICKS_HALF : integer := TICKS_CYC / 2; variable divider : integer range 0 to TICKS_HALF-1 := TICKS_HALF-1; begin if rising_edge(clk) then DCLK <= toggle; if ( (divider - 1) < 0 ) then divider := (TICKS_HALF-1); toggle := not toggle; else divider := divider - 1; end if; end if; end process MAKE_DC_DC; ---------------------------------------------------------------------- -- Rob Gaddi, Highland Technology Email address is currently out of order
XST Makes Odd Choice
Started by ●January 27, 2009
Reply by ●January 27, 20092009-01-27
Rob Gaddi wrote: ...> Then I synthesize the whole thing and, just for fun, go spelunking in > the FPGA editor to see how it built the logic. As expected, it's a 7 > bit downcounter, implemented using the carry chain. And yet the > zero-detection logic, rather than using the perfectly good carry-out > signal from the decrement chain, is being implemented with an 8 input > NOR, split across several slices.> Anyone care to speculate why?The divider register is updated by an adder. The toggle register is updated by the same adder, follow by a comparison. I expect that synthesis will cascade the adder and compare rather than duplicate the adder. -- Mike Treseler ps: save a register by moving the port assignment just before the "end process"
Reply by ●January 27, 20092009-01-27
On Jan 27, 2:02 pm, Rob Gaddi <rga...@technologyhighland.com> wrote:> I'm working in a Spartan 3 with XST 10.1. I'm trying to divide down a > 32 MHz clock to make a 128 kHz clock on the DCLK output pin. I'm > implementing it with a downcounter that (resets itself and toggles the > pin) when it gets to zero. Nothing tricky there so far. > > Then I synthesize the whole thing and, just for fun, go spelunking in > the FPGA editor to see how it built the logic. As expected, it's a 7 > bit downcounter, implemented using the carry chain. And yet the > zero-detection logic, rather than using the perfectly good carry-out > signal from the decrement chain, is being implemented with an 8 input > NOR, split across several slices. > > Of course, this still works. At 32 MHz I could ship each individual > bit to Taiwan on a barge and wait for the answer by carrier pidgeon and > it would still work. But it seems like an odd choice to have made. By > my guesstimations it's both larger and slower than using the carry-out. > > Anyone care to speculate why? > -- Rob > > ---------------------------------------------------------------------- > > MAKE_DC_DC: process(clk) > > variable toggle : std_logic := '0'; > > constant TICKS_CYC : integer := 32_000_000 / 128_000; > constant TICKS_HALF : integer := TICKS_CYC / 2; > > variable divider : integer > range 0 to TICKS_HALF-1 := TICKS_HALF-1; > > begin > if rising_edge(clk) then > DCLK <= toggle; > > if ( (divider - 1) < 0 ) then > divider := (TICKS_HALF-1); > toggle := not toggle; > > else > divider := divider - 1; > end if; > end if; > end process MAKE_DC_DC; > > ---------------------------------------------------------------------- > > -- > Rob Gaddi, Highland Technology > Email address is currently out of orderI see your point. 'divider' is an integer, so all it *should* have to do is check the sign bit at this statement: "if ( (divider - 1) < 0 ) then" But you say it's not. I'm guessing XST is smart enough to infer a counter with "divider := divider - 1;", but not smart enough to infer carry-out. Looks like there is room for improvement. AL PS: Try it with the counter operation outside of the clock process: ... divider_1 := divider-1 ... if (divider_1 < 0) ... ... else divider := divider_1; ...
Reply by ●January 27, 20092009-01-27
"Rob Gaddi":> Of course, this still works. At 32 MHz I could ship each individual > bit to Taiwan on a barge and wait for the answer by carrier pidgeon and > it would still work. But it seems like an odd choice to have made. By > my guesstimations it's both larger and slower than using the carry-out.Really?> variable divider : integer > range 0 to TICKS_HALF-1 := TICKS_HALF-1;> ...> if ( (divider - 1) < 0 ) then > divider := (TICKS_HALF-1);When, per definition, is a positive varibale decremented by one less than zero? Maybe if the decrement leads to a high MSB. just like the set/reset in the example does? I'm really not sure about this (don't have the money to buy expensive standard specifications, and also prefer verilog). Gruss Jan Bruns
Reply by ●January 27, 20092009-01-27
On Jan 27, 1:02=A0pm, Rob Gaddi <rga...@technologyhighland.com> wrote:> I'm working in a Spartan 3 with XST 10.1. =A0I'm trying to divide down a > 32 MHz clock to make a 128 kHz clock on the DCLK output pin. I'm > implementing it with a downcounter that (resets itself and toggles the > pin) when it gets to zero. Nothing tricky there so far. > > Then I synthesize the whole thing and, just for fun, go spelunking in > the FPGA editor to see how it built the logic. =A0As expected, it's a 7 > bit downcounter, implemented using the carry chain. =A0And yet the > zero-detection logic, rather than using the perfectly good carry-out > signal from the decrement chain, is being implemented with an 8 input > NOR, split across several slices. > > Of course, this still works. =A0At 32 MHz I could ship each individual > bit to Taiwan on a barge and wait for the answer by carrier pidgeon and > it would still work. =A0But it seems like an odd choice to have made. =A0=By> my guesstimations it's both larger and slower than using the carry-out. > > Anyone care to speculate why? > -- Rob > > ---------------------------------------------------------------------- > > MAKE_DC_DC: process(clk) > > variable toggle =A0 =A0 : std_logic :=3D '0'; > > constant TICKS_CYC =A0: integer :=3D 32_000_000 / 128_000; > constant TICKS_HALF : integer :=3D TICKS_CYC / 2; > > variable divider =A0 =A0: integer > =A0 =A0 range 0 to TICKS_HALF-1 :=3D TICKS_HALF-1; > > begin > =A0 =A0 if rising_edge(clk) then > =A0 =A0 =A0 =A0 DCLK =A0 =A0<=3D toggle; > > =A0 =A0 =A0 =A0 if ( (divider - 1) < 0 ) then > =A0 =A0 =A0 =A0 =A0 =A0 divider :=3D (TICKS_HALF-1); > =A0 =A0 =A0 =A0 =A0 =A0 toggle =A0:=3D not toggle; > > =A0 =A0 =A0 =A0 else > =A0 =A0 =A0 =A0 =A0 =A0 divider :=3D divider - 1; > =A0 =A0 =A0 =A0 end if; > =A0 =A0 end if; > end process MAKE_DC_DC; > > ---------------------------------------------------------------------- > > -- > Rob Gaddi, Highland Technology > Email address is currently out of orderRob, you need to divide 32 MHz by 250, whichis not an integer power of 2, and it takes an 8-bit counter. There are many different ways to do this efficiently. Peter Alfke
Reply by ●January 27, 20092009-01-27
On Wed, 28 Jan 2009 00:54:36 +0100, "Jan Bruns" <testzugang_janbruns@arcor.de> wrote:> >"Rob Gaddi": >> Of course, this still works. At 32 MHz I could ship each individual >> bit to Taiwan on a barge and wait for the answer by carrier pidgeon and >> it would still work. But it seems like an odd choice to have made. By >> my guesstimations it's both larger and slower than using the carry-out. > >Really? > >> variable divider : integer >> range 0 to TICKS_HALF-1 := TICKS_HALF-1; > >> ... > >> if ( (divider - 1) < 0 ) then >> divider := (TICKS_HALF-1); > > >When, per definition, is a positive varibale decremented by one >less than zero? Maybe if the decrement leads to a high MSB. just >like the set/reset in the example does? > >I'm really not sure about this (don't have the money to buy >expensive standard specifications, and also prefer verilog).An integer is a signed entity so if you're decrementing it, the first time n-1 becomes less than zero is when n == 0. I think the idea was that divider reg would get a decrement operator generator by carry chain and then the final carry being set would indicate n-1 becoming negative. It's a cute idea but synthesizer probably is not smart enough to do operator sharing at the output of the decrementer and instead builds a zero decoder at the output of the register. -- Muzaffer Kal DSPIA INC. ASIC/FPGA Design Services http://www.dspia.com
Reply by ●January 27, 20092009-01-27
Peter Alfke wrote:> Rob, you need to divide 32 MHz by 250, whichis not an integer power of > 2, and it takes an 8-bit counter.He did use 25: constant TICKS_CYC : integer := 32_000_000 / 128_000; The question is synthesis of the count down to zero. I expect that the code synthesizes ok. However, carry chains vs plain LUTs is up to the default constraints. -- Mike Treseler
Reply by ●January 27, 20092009-01-27
On Tue, 27 Jan 2009 13:02:38 -0800, Rob Gaddi wrote:> I'm working in a Spartan 3 with XST 10.1. I'm trying to divide down a > 32 MHz clock to make a 128 kHz clock on the DCLK output pin. I'm > implementing it with a downcounter that (resets itself and toggles the > pin) when it gets to zero. Nothing tricky there so far. > > Then I synthesize the whole thing and, just for fun, go spelunking in > the FPGA editor to see how it built the logic. As expected, it's a 7 > bit downcounter, implemented using the carry chain. And yet the > zero-detection logic, rather than using the perfectly good carry-out > signal from the decrement chain, is being implemented with an 8 input > NOR, split across several slices. > > Of course, this still works. At 32 MHz I could ship each individual bit > to Taiwan on a barge and wait for the answer by carrier pidgeon and it > would still work. But it seems like an odd choice to have made. By my > guesstimations it's both larger and slower than using the carry-out. > > Anyone care to speculate why? > -- Rob > > ---------------------------------------------------------------------- > > MAKE_DC_DC: process(clk) > > variable toggle : std_logic := '0'; > > constant TICKS_CYC : integer := 32_000_000 / 128_000; constant > TICKS_HALF : integer := TICKS_CYC / 2; > > variable divider : integer > range 0 to TICKS_HALF-1 := TICKS_HALF-1; > > begin > if rising_edge(clk) then > DCLK <= toggle; > > if ( (divider - 1) < 0 ) then > divider := (TICKS_HALF-1); > toggle := not toggle; > > else > divider := divider - 1; > end if; > end if; > end process MAKE_DC_DC; > > ----------------------------------------------------------------------I always add 1 bit to my counters and the use the MSB to do the reset, for example if I wanted to divide by 256 I'd do, reg [8:0] cntr; always@(posedge clk) begin if(sync_rst || cntr[8]) begin cntr <= 1; end else begin cntr <= cntr + 1; end This forces the synthesizer to use the sync set/reset inputs and the reset path will only have 1 LUT delay in it.
Reply by ●January 28, 20092009-01-28
"Muzaffer Kal":> An integer is a signed entity so if you're decrementing it, the first > time n-1 becomes less than zero is when n == 0. I think the idea was > that divider reg would get a decrement operator generator by carry > chain and then the final carry being set would indicate n-1 becoming > negative. It's a cute idea but synthesizer probably is not smart > enough to do operator sharing at the output of the decrementer and > instead builds a zero decoder at the output of the register.Ah, ok. Would this still apply if n was an array of signals? Gruss Jan Bruns
Reply by ●January 28, 20092009-01-28
On Jan 27, 9:50 pm, General Schvantzkoph <schvantzk...@yahoo.com> wrote:> > > ---------------------------------------------------------------------- > > > MAKE_DC_DC: process(clk) > > > variable toggle : std_logic := '0'; > > > constant TICKS_CYC : integer := 32_000_000 / 128_000; constant > > TICKS_HALF : integer := TICKS_CYC / 2; > > > variable divider : integer > > range 0 to TICKS_HALF-1 := TICKS_HALF-1; > > > begin > > if rising_edge(clk) then > > DCLK <= toggle; > > > if ( (divider - 1) < 0 ) then > > divider := (TICKS_HALF-1); > > toggle := not toggle; > > > else > > divider := divider - 1; > > end if; > > end if; > > end process MAKE_DC_DC; > > > ---------------------------------------------------------------------- > > I always add 1 bit to my counters and the use the MSB to do the reset, > for example if I wanted to divide by 256 I'd do, > > reg [8:0] cntr; > > always@(posedge clk) begin > if(sync_rst || cntr[8]) begin > cntr <= 1; > end > else begin > cntr <= cntr + 1; > end > > This forces the synthesizer to use the sync set/reset inputs and the > reset path will only have 1 LUT delay in it.I tend to think in terms of hardware and once I know exactly what I want from the hardware, I "describe" this in the HDL. In this case, the carry out is not registered, so it can't really be described inside the clocked process. I hedge with the word "really" because this may be possible with the right coding style using variables. But I prefer not to bother too much with "tricky" coding styles and to use templates I have the most confidence in. So I would code the counter logic as combinatorial logic and then assign it to a register. Of course I can't say for sure this will give you what you want, but I think it has a good chance. constant TICKS_CYC : integer := 32_000_000 / 128_000; constant TICKS_HALF : integer := TICKS_CYC / 2; signal downcntr : integer range -1 to TICKS_HALF-1 := TICKS_HALF-1; signal divider... toggle... togglecntr... MAKE_DC_DC: process(divider, toggle) begin if rising_edge(clk) then DCLK <= toggle; downcntr <= divider - 1; if (downcntr < 0) then divider := (TICKS_HALF-1); togglecntr := not toggle; else divider := divider - 1; end if; end if; end process MAKE_DC_DC; MAKE_DC_DC: process(clk) begin if rising_edge(clk) then divider := mod(downcntr, TICKS_HALF); toggle := togglecntr; end if; end process MAKE_DC_DC; If this form gives you the carry test that you are looking for, then maybe you can combine the two processes into one and get the same logic. The trick will be to use variable assignments to set the variable and compared to -1 before the final assignment that is latched into the register. I haven't tested any of this, so I may be all washed up. I don't typically use variables. I'm actually more interested in the fact that you consider "spelunking" in the FPGA editor to be "fun"... ;^) Rick




