Counting number of asserted register bits in VHDL

Discussion in 'VHDL' started by bucketonuts@gmail.com, May 14, 2013.

  1. Guest

    Hello,

    I have a status register of width, R_SIZE. This is a generic so the register width may be different depending on the application. The R_SIZE is limited to values, 4, 8 and 16.

    Each bit in the register is set by different module as an indication of that module's done status. These status bits are asserted for only one clock and may be asserted again as each module may run its application multiple times on different data.

    I need to count the number of bits set in the status register on each clock and accumulate a total to match a predetermined "max" value.

    I thought I'd use the VHDL 'generate' statement to compile RTL based on R_SIZE as follows.

    =================== start RTL =====================
    architecture behave of b is

    component modx port(
    mod_cmplt : out std_logic
    );
    end component modx;

    signal mod_cmplt : std_logic_vector(15 downto 0);
    signal cmplt_cnt : integer range 0 to 512;
    signal next_cmplt_cnt : integer range 0 to 512;

    begin
    mod_cmplt(15 downto R_SIZE) <= (others => '0');

    g1: for i in 0 to R_SIZE-1 generate
    u_modx : modx port map(
    mod_cmplt => mod_cmplt(i)
    );
    end generate;

    process (mod_cmplt, cmplt_cnt)
    begin
    next_cmplt_cnt <= cmplt_cnt;

    gen4: if R_SIZE = 4 generate
    next_cmplt_cnt <= mod_cmplt(0) + mod_cmplt(1) + mod_cmplt(2) +
    mod_cmplt(3) + cmplt_cnt;
    end generate;

    gen8: if R_SIZE = 8 generate
    next_cmplt_cnt <= mod_cmplt(0) + mod_cmplt(1) + mod_cmplt(2) +
    mod_cmplt(3) + mod_cmplt(4) + mod_cmplt(5) +
    mod_cmplt(6) + mod_cmplt(7) + cmplt_cnt;
    end generate;

    gen16:if R_SIZE = 16 generate
    next_cmplt_cnt <= mod_cmplt(0) + mod_cmplt(1) + mod_cmplt(2) +
    mod_cmplt(3) + mod_cmplt(4) + mod_cmplt(5) +
    mod_cmplt(6) + mod_cmplt(7) + mod_cmplt(8) +
    mod_cmplt(9) + mod_cmplt(10) + mod_cmplt(11) +
    mod_cmplt(12) + mod_cmplt(13) + mod_cmplt(14) +
    mod_cmplt(15) + cmplt_cnt;
    end generate

    end process;

    process (reset, clk)
    begin
    if (reset = '1') then
    cmplt_cnt <= 0;
    elsif (clk'event and clk='1')
    cmplt_cnt <= next_cmplt_cnt;
    end if;
    end process

    end behave;
    ================================ end RTL =================

    The first error I get is a syntax error:

    Error-[IEEEVHDLSYNTAXERR] Syntax error

    gen4: if R_SIZE = 4 generate
    ^
    Syntax error detected during VHDL parsing.

    I don't know what to do about this. Is there a better way to code what I want the system to do?

    Thank you.
    , May 14, 2013
    #1
    1. Advertising

  2. GaborSzakacs Guest

    wrote:
    > Hello,
    >
    > I have a status register of width, R_SIZE. This is a generic so the register width may be different depending on the application. The R_SIZE is limited to values, 4, 8 and 16.
    >
    > Each bit in the register is set by different module as an indication of that module's done status. These status bits are asserted for only one clock and may be asserted again as each module may run its application multiple times on different data.
    >
    > I need to count the number of bits set in the status register on each clock and accumulate a total to match a predetermined "max" value.
    >
    > I thought I'd use the VHDL 'generate' statement to compile RTL based on R_SIZE as follows.
    >
    > =================== start RTL =====================
    > architecture behave of b is
    >
    > component modx port(
    > mod_cmplt : out std_logic
    > );
    > end component modx;
    >
    > signal mod_cmplt : std_logic_vector(15 downto 0);
    > signal cmplt_cnt : integer range 0 to 512;
    > signal next_cmplt_cnt : integer range 0 to 512;
    >
    > begin
    > mod_cmplt(15 downto R_SIZE) <= (others => '0');
    >
    > g1: for i in 0 to R_SIZE-1 generate
    > u_modx : modx port map(
    > mod_cmplt => mod_cmplt(i)
    > );
    > end generate;
    >
    > process (mod_cmplt, cmplt_cnt)
    > begin
    > next_cmplt_cnt <= cmplt_cnt;
    >
    > gen4: if R_SIZE = 4 generate
    > next_cmplt_cnt <= mod_cmplt(0) + mod_cmplt(1) + mod_cmplt(2) +
    > mod_cmplt(3) + cmplt_cnt;
    > end generate;
    >
    > gen8: if R_SIZE = 8 generate
    > next_cmplt_cnt <= mod_cmplt(0) + mod_cmplt(1) + mod_cmplt(2) +
    > mod_cmplt(3) + mod_cmplt(4) + mod_cmplt(5) +
    > mod_cmplt(6) + mod_cmplt(7) + cmplt_cnt;
    > end generate;
    >
    > gen16:if R_SIZE = 16 generate
    > next_cmplt_cnt <= mod_cmplt(0) + mod_cmplt(1) + mod_cmplt(2) +
    > mod_cmplt(3) + mod_cmplt(4) + mod_cmplt(5) +
    > mod_cmplt(6) + mod_cmplt(7) + mod_cmplt(8) +
    > mod_cmplt(9) + mod_cmplt(10) + mod_cmplt(11) +
    > mod_cmplt(12) + mod_cmplt(13) + mod_cmplt(14) +
    > mod_cmplt(15) + cmplt_cnt;
    > end generate
    >
    > end process;
    >
    > process (reset, clk)
    > begin
    > if (reset = '1') then
    > cmplt_cnt <= 0;
    > elsif (clk'event and clk='1')
    > cmplt_cnt <= next_cmplt_cnt;
    > end if;
    > end process
    >
    > end behave;
    > ================================ end RTL =================
    >
    > The first error I get is a syntax error:
    >
    > Error-[IEEEVHDLSYNTAXERR] Syntax error
    >
    > gen4: if R_SIZE = 4 generate
    > ^
    > Syntax error detected during VHDL parsing.
    >
    > I don't know what to do about this. Is there a better way to code what I want the system to do?
    >
    > Thank you.
    >


    I'm not up enough on VHDL to tell you if it's even valid
    to have generate statements within a process, but the point is
    that you don't need them here. Since mod_cmplt is always the
    same size regardless of the value of R_SIZE, you can just use
    if ... elsif ... else without the generates. Or even use a case
    statement. Basically there's nothing in your equations that
    requires generate statements. And note that because R_SIZE is
    known at compile time it won't create extra logic.

    --
    Gabor
    GaborSzakacs, May 14, 2013
    #2
    1. Advertising

  3. Guest

    Yeah, it seems like something much simpler like this would work fine:

    process (reset, clk)
    variable sum : integer := 0;
    begin
    if (reset = '1') then
    cmplt_cnt <= 0;
    elsif (clk'event and clk='1')
    for k in 0 to R_SIZE - 1 loop
    sum := sum + mod_cmplt(k);
    end loop;
    cmplt_cnt <= cmplt_cnt + sum;
    end if;
    end process;
    , May 15, 2013
    #3
  4. Guest

    On Tuesday, May 14, 2013 4:52:31 PM UTC-4, Gabor Sz wrote:
    >
    >
    >
    > I'm not up enough on VHDL to tell you if it's even valid
    >
    > to have generate statements within a process, but the point is
    >
    > that you don't need them here. Since mod_cmplt is always the
    >
    > same size regardless of the value of R_SIZE, you can just use
    >
    > if ... elsif ... else without the generates. Or even use a case
    >
    > statement. Basically there's nothing in your equations that
    >
    > requires generate statements. And note that because R_SIZE is
    >
    > known at compile time it won't create extra logic.
    >
    >
    >
    > --
    >
    > Gabor


    Thank you. I thought about this but didn't know what would happen to the adder if only 8 modx modules were instantiated. Even though the if-else branch for 16 modx's wouldn't be reached, the adder would still have inputs for modx[8]to modx[15] which would not be driven.
    Also, you are correct, generate statements may not be located in a process.
    Thanks again.
    , May 15, 2013
    #4
  5. Guest

    On Tuesday, May 14, 2013 7:05:00 PM UTC-4, wrote:
    > Yeah, it seems like something much simpler like this would work fine:
    >
    >
    >
    > process (reset, clk)
    >
    > variable sum : integer := 0;
    >
    > begin
    >
    > if (reset = '1') then
    >
    > cmplt_cnt <= 0;
    >
    > elsif (clk'event and clk='1')
    >
    > for k in 0 to R_SIZE - 1 loop
    >
    > sum := sum + mod_cmplt(k);
    >
    > end loop;
    >
    > cmplt_cnt <= cmplt_cnt + sum;
    >
    > end if;
    >
    > end process;


    Thank you - this looks interesting. So sum gets evaluated at clk'event in time for cmplt_cnt to be updated with the new value of sum?
    , May 15, 2013
    #5
  6. GaborSzakacs Guest

    wrote:
    > On Tuesday, May 14, 2013 4:52:31 PM UTC-4, Gabor Sz wrote:
    >>
    >>
    >> I'm not up enough on VHDL to tell you if it's even valid
    >>
    >> to have generate statements within a process, but the point is
    >>
    >> that you don't need them here. Since mod_cmplt is always the
    >>
    >> same size regardless of the value of R_SIZE, you can just use
    >>
    >> if ... elsif ... else without the generates. Or even use a case
    >>
    >> statement. Basically there's nothing in your equations that
    >>
    >> requires generate statements. And note that because R_SIZE is
    >>
    >> known at compile time it won't create extra logic.
    >>
    >>
    >>
    >> --
    >>
    >> Gabor

    >
    > Thank you. I thought about this but didn't know what would happen to the adder
    > if only 8 modx modules were instantiated. Even though the if-else

    branch for
    > 16 modx's wouldn't be reached, the adder would still have inputs for

    modx[8]
    > to modx[15] which would not be driven.
    > Also, you are correct, generate statements may not be located in a process.
    > Thanks again.


    Actually the adder would not have extra undriven inputs _because_ those
    branches are not reached, and the synthesizer only implements code that
    is reached. For the cases where you don't have the maximum R_SIZE,
    there would be some unused (and undriven) signals, but these would
    generally get trimmed at or after physical synthesis. If you used
    the other example with a loop, you could size the mod_cmplt vector
    using R_SIZE and then there would be no unused signals. If you like
    to avoid warnings during synthesis and build, then that is a cleaner
    approach.

    --
    Gabor
    GaborSzakacs, May 15, 2013
    #6
  7. Andy Guest

    A nice little problem to illustrate VHDL RTL...

    I don't know if it makes a real difference, but constraining the range of sum is seldom a bad idea:

    variable sum : natural range 0 to mod_cmplt'length;

    Don't forget to initialize sum to 0 before the loop, on every clock cycle. Variable declaration initializations in processes only happen once, at time0.

    Also, syntactic tricks are required to add a std_logic bit to an integer and get an integer result:

    sum := sum + to_integer(unsigned(0 => mod_cmplt(k)));

    Or simply:

    if mod_complt(k) = '1' then
    sum := sum + 1;
    end if;

    Since cmplt_cnt is an integer, you need to make sure it never overflows. Presumably it would be set to zero once it reaches some limit where somethinghappens. If you want cmplt_cnt to roll over, either use mod (modulo operator) or make cmplt_cnt an unsigned instead of integer type (sum can still beinteger, and it cannot overflow).

    More syntactic sugar: when iterating in a loop over the range of a vector, use vector'range as the loop index range:

    for k in mod_cmplt'range loop

    Finally, if you want to pipeline the sum and cmplt_cnt updates, just updatecnt_cmplt before sum is initialized:

    pipelined: process (rst, clk) is
    variable sum : natural range 0 to mod_cmplt'length;
    begin
    if rst = '1' then
    cmplt_cnt <= 0;
    sum := 0; -- used as register, so reset it
    elsif rising_edge(clk) then
    cmplt_cnt <= cmplt_cnt + sum; -- sum is register here
    sum := 0; -- sum is combinatorial hereafter
    for k in mod_complt'range loop
    sum := sum + to_integer(unsigned(0 => mod_cmplt(k)));
    end loop;
    end if;
    end process pipelined;

    Andy
    Andy, May 15, 2013
    #7
  8. Guest

    On Wednesday, May 15, 2013 11:47:16 AM UTC-4, Andy wrote:
    > A nice little problem to illustrate VHDL RTL...
    >
    >
    >
    > I don't know if it makes a real difference, but constraining the range ofsum is seldom a bad idea:
    >
    >
    >
    > variable sum : natural range 0 to mod_cmplt'length;
    >
    >
    >
    > Don't forget to initialize sum to 0 before the loop, on every clock cycle.. Variable declaration initializations in processes only happen once, at time 0.
    >
    >
    >
    > Also, syntactic tricks are required to add a std_logic bit to an integer and get an integer result:
    >
    >
    >
    > sum := sum + to_integer(unsigned(0 => mod_cmplt(k)));
    >
    >
    >
    > Or simply:
    >
    >
    >
    > if mod_complt(k) = '1' then
    >
    > sum := sum + 1;
    >
    > end if;
    >
    >
    >
    > Since cmplt_cnt is an integer, you need to make sure it never overflows. Presumably it would be set to zero once it reaches some limit where something happens. If you want cmplt_cnt to roll over, either use mod (modulo operator) or make cmplt_cnt an unsigned instead of integer type (sum can still be integer, and it cannot overflow).
    >
    >
    >
    > More syntactic sugar: when iterating in a loop over the range of a vector, use vector'range as the loop index range:
    >
    >
    >
    > for k in mod_cmplt'range loop
    >
    >
    >
    > Finally, if you want to pipeline the sum and cmplt_cnt updates, just update cnt_cmplt before sum is initialized:
    >
    >
    >
    > pipelined: process (rst, clk) is
    >
    > variable sum : natural range 0 to mod_cmplt'length;
    >
    > begin
    >
    > if rst = '1' then
    >
    > cmplt_cnt <= 0;
    >
    > sum := 0; -- used as register, so reset it
    >
    > elsif rising_edge(clk) then
    >
    > cmplt_cnt <= cmplt_cnt + sum; -- sum is register here
    >
    > sum := 0; -- sum is combinatorial hereafter
    >
    > for k in mod_complt'range loop
    >
    > sum := sum + to_integer(unsigned(0 => mod_cmplt(k)));
    >
    > end loop;
    >
    > end if;
    >
    > end process pipelined;
    >
    >
    >
    > Andy


    Thanks, Andy. I'm new to VHDL. It took me most of the morning to figure outhow to add a std_logic bit to an integer (to_integer). You make some very good points in the rest of your post as well.
    , May 15, 2013
    #8
  9. Guest

    Andy,
    Thanks--I wasn't sure if the variable had to be initialized to zero. I don't use variables often.

    I elided the type conversion in my code snippet (even though that's where Ispend half my VHDL development time). I tried your std_logic->integer conversion above and Synplify didn't seem to be liking it, and I ended up having to do a ridiculous conversion like this:

    sum := sum + to_integer(unsigned(std_logic_vector'(0=>mod_cmplt(k))));

    This is why Verilog is awesome. You want to add a real number and the msb of an integer and a slice of a character string? No problem; no conversions required.
    -Kevin
    , May 16, 2013
    #9
  10. Le 16/05/2013 21:42, a écrit :

    > This is why Verilog is awesome. You want to add a real number and the msb of an integer and
    > a slice of a character string? No problem; no conversions required.


    That's weak typing's advantage. But it lets you so easily shoot yourself
    in the foot...

    Nicolas
    Nicolas Matringe, May 16, 2013
    #10
  11. Andy Guest

    Kevin,

    Did you try to_integer(unsigned'(0 => mod_cmplt(k)))?

    I usually use the if statement anyway. Much more readable.

    Verilog: "Hold my beer and watch this!"

    Andy
    Andy, May 17, 2013
    #11
  12. Guest

    Andy: Yes, that does work, with the unsigned cast (using ') instead of the unsigned function. I don't really know the difference, but the cast does work.
    -Kevin
    , May 17, 2013
    #12
  13. Andy Guest

    Kevin, leaving out the ' was an unfortunate typo in my original suggestion.

    Unsigned() is a built-in type conversion function from any closely related type to unsigned (a cast). In order for it to work, the argument must be statically determinable to be of a single type that is acceptable for the converion function.

    The problem is (0 => [std_logic expression]) could be any of: slv, sulv, signed or unsigned, and perhaps others if additional packages are used. More importantly, all of those potential types are closely related to unsigned and allowable arguments for unsigned(). Thus the compiler cannot make a unique determination of which ONE of those types to use, so it throws an error (even though we know it really would not make a difference in the end).

    Unsigned'() is a type designator. The type designator tells the compiler that the following anonymous expression IS of the type indicated. It is used when the following anonymous expression could be numerous types that would all "work", but VHDL needs to know which ONE of those that "will work" it should use.

    Hope this helps,

    Andy
    Andy, May 17, 2013
    #13
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. sarmin kho
    Replies:
    2
    Views:
    826
    A. Lloyd Flanagan
    Jun 15, 2004
  2. Miki Tebeka
    Replies:
    1
    Views:
    445
    Marcin 'Qrczak' Kowalczyk
    Jun 14, 2004
  3. Frank Buss
    Replies:
    3
    Views:
    4,068
    Mike Treseler
    Jul 31, 2006
  4. Mack

    Count number of bits set in a number

    Mack, Sep 27, 2007, in forum: C Programming
    Replies:
    12
    Views:
    813
    Mark Bluemel
    Sep 28, 2007
  5. Dale Dellutri
    Replies:
    9
    Views:
    1,079
    dfighter
    Apr 4, 2009
Loading...

Share This Page