2

I am working in hardware domain. I need to generate all nCk combinations of numbers from 0 to n-1. It is easy to do it using software but this is to be done using HDL - VHDL. I cannot spend much on computational complexity and need to generate at the rate of 1 sample/second (1 clk cycle per combination). Intermediate memory is available.

Eg:- suppose for 6C4, I need to generate

(1,2,3,4) (1,2,3,5) (1,2,3,6) (1,2,4,5) (1,2,4,6) (1,2,5,6) (1,3,4,5) (1,3,4,6) (1,3,5,6) (1,4,5,6) (2,3,4,5) (2,3,4,6) (2,3,5,6) (2,4,5,6) (3,4,5,6)

Order is important.

Edit: 'k' and 'n' are always even. Is there some way to simplify the logic taking this into consideration.

In this case 'n' and 'k' inputs to the entity may vary('n' with a upper limit of 16)

Maximus
  • 143
  • 3
  • 12
  • 1
    Why not try doing this with "carries". Each clock, increment the last number. If the last number hits `n`, then add one to the previous number and reset the last number, etc. –  Jan 21 '14 at 02:32

1 Answers1

2

This is basically asking for an N-digit number in base-M (in your example, 4-digit base 6).

Given that you have storage available, you can basically define a 0..M counter something like this:

entity counter is
    port(reset : in std_logic; 
         clock : in std_logic;
         count : inout std_logic_vector(2 downto 0);
         carry : out std_logic);

architecture behavioral of counter is
begin
    process(reset, clock) is
    begin
        if reset = '1' then
            count <= "000";
            carry <= '0';
        else if clock = '1' and clock'event then
            count <= (count + 1) mod 6;
            if count = "000" then
                carry <= '1';
            else
                carry <= '0';
            end if;
        end if;
    end process;
end behavioral;

Then you instantiate N of those counters. You'll wire the system clock to the clock input of the right-hand one (least significant digit) of the N counters. For each successive counter, you'll wire the carry out from the less significant digit's counter to the clock input of the next more significant digit's counter.

You'll then have one more bit of circuitry to drive the reset lines of the individual counters from the inclusive-or of the system reset and the carry-out from the counter for the most significant bit (so you start from 0 at system reset, and also wrap around to 0000 when you reach the limit for all digits).

If your maximum isn't a constant, you need to specify a set of inputs for the maximum, and only wrap around when your current count = the maximum count:

entity counter is
    port (reset : in std_logic;
          clock : in std_logic;
          count : inout std_logic_vector(3 downto 0);
          carry : out std_logic;
          max   : in std_logic_vector(3 downto 0));

-- ...

count <= count + 1;
if count = max then
     count <= "0000";
     carry <= '1';
else
     carry <= '0';
end if;

There are, of course, a few other minor details--I've set the size of counter to 3 bits "by hand", based on a maximum value of 6 for an individual digit. If you're likely to need a lot of these, you can/could create a generic component that lets you specify the limit in the instantiation and (if memory serves) compute the number of bits necessary for that range of counter. That tends to obfuscate the code a bit though, and I'd guess this is adequate for the moment. I've also set it up with the output little endian. If you want it big-endian, you'd change it to a std_logic_vector(0 to 2) instead (at least if I recall correctly--it seems right, but it's been a long time since I wrote any big-endian logic).

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • I agree with your answer.1) But instantiating the above entity can be done if my 'k' is a constant. But in my case 'n' and 'k' are variables('n' with a upper limit of 16). I think that 'n' can be dealt with by giving it as input to the counter. But how do we deal with the variable 'k'? Obviously we cant instantiate them repeatedly. I think we should reuse the counter and save each state in memory before going to the next index. 2)'k' and 'n' are always even. Is there some way to simplify the logic taking this into consideration. – Maximus Jan 21 '14 at 06:35
  • 3) As explained above, all counters is reset to 0. But in my case I need only combinations(not permutation!!) of indices, I should reset the counter of higher index, say 'i' to the 'count(i-1) + 2' because 'i-1'th index itself is updated to 'count(i-1) + 1'. Also that unlike in the usual n-bit counter with asynchronous clock, I think that the lower index should be reset first and higher index should be reset with respect to that. – Maximus Jan 21 '14 at 06:49
  • Only the 'k'th index will go till 'n' as values are not repeated, and 'k-1'th index till 'n-1' and so on. I think that the parameter for modulo operation should be the count of the higher index?? – Maximus Jan 21 '14 at 06:49
  • @BastinJoseph: I've edited to deal with a variable maximum. To get a variable number of digits, you'd basically modify your reset logic a little, so you base the reset on the carry from any digit you prefer instead of just the most significant one. You can reduce the circuitry a little for even numbers by only having N-1 inputs, and hard-wiring the LSB to 0. Combinations vs. permutations requires a per-digit maximum (n, n-1, n-2, etc.) and per-digit offset (add 0 to most significant, 1 to next most significant, etc. – Jerry Coffin Jan 21 '14 at 07:24
  • Thank you sir. Since my 'k' is variable (need to generate 'k' digits) and can be as big as 14 (if 'n' = 16), it is not feasible to use 14 counters(which can work for even the worst case and disabling some of them when not needed) in the hardware. Is there some way of reusing the counter – Maximus Jan 21 '14 at 07:35
  • 1
    @BastinJoseph: It's possible to reuse the counter circuitry, but somewhat non-trivial, and getting results in a single clock can be fairly difficult. Bottom line: given that a single counter is really just a 4-bit adder plus a 4-bit comparator, re-using a single counter for more than one digit may easily use more circuitry than it saves. – Jerry Coffin Jan 21 '14 at 07:45
  • Thank you sir. That pretty much clears my doubts. One more thing. When I mentioned that 'n' and 'k' are always even, I meant that we need to deal will **even number of digits**. But in any case,a particular digit can take any value from 0 to 'n-1'.Is there a way of simplification. – Maximus Jan 21 '14 at 07:52
  • 1
    @BastinJoseph: If `n` is always even, then the LSB of `n` will be 0, so you can hard-wire it as a `0`. Not much more than that you can do (and it's probably questionable whether that's worthwhile). – Jerry Coffin Jan 21 '14 at 08:10
  • Thank you sir for your time and effort – Maximus Jan 21 '14 at 08:29
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/45733/discussion-between-bastin-joseph-and-jerry-coffin) – Maximus Jan 21 '14 at 17:33