5
\$\begingroup\$

As part of an assignment, I must create these blocks that tie in to a larger top level module. (there are more blocks not pictured). I have everything working fine, except this UP/DOWN counter because I can't really work out how this can possibly be implemented without a CLK.

enter image description here

The EN_UP and EN_DOWN signals are simple pulses that should increment or decrement an internal 16-bit value, which gets split into nibbles and put on the output. I feel as if this should be fairly simple, but I can't work this out.

I've tried multiple approaches.

1) - Inside a single process

count : PROCESS (RESET, EN_UP, EN_DOWN)
BEGIN
    if(RESET = '1') then
        countSignal <= x"0000";
    elsif(rising_edge(EN_UP) and EN_DOWN = '0') then
        countSignal <= countSignal + 1;
    elsif(rising_edge(EN_DOWN) and EN_UP = '0') then
        countSignal <= countSignal - 1;
    end if;
END PROCESS;

This ultimately compiles with no errors or warnings, however the compiler ends up creating the wrong circuit, tying the EN_UP to the CLK of the flip-flip, and the EN_DOWN to the CE (clock enable). While yes, that is part of the equation, it doesn't mirror that for the opposite case.

2) - Separate processes

countUP : PROCESS (RESET, EN_UP)
BEGIN
    if(RESET = '1') then
        countSignal <= x"0000";
    elsif(rising_edge(EN_UP) and EN_DOWN = '0') then
        countSignal <= countSignal + 1;
    end if;
END PROCESS;

countDOWN : PROCESS (RESET, EN_DOWN)
BEGIN
    if(RESET = '1') then
        countSignal <= x"0000";
    elsif(rising_edge(EN_DOWN) and EN_UP = '0') then
        countSignal <= countSignal - 1;
    end if;
END PROCESS;

This results in: Signal countSignal[15] in unit UD_COUNTER is connected to following multiple drivers:

3) Multiple processes with Hi-Z states

I tried some attempt with Hi-Z which also failed.

\$\endgroup\$
6
\$\begingroup\$

You're right in thinking that you will have to use something for a clock for the counter. Otherwise there is nothing to tell it when to count. Either the clock is missing from the diagram, or you will have to edge-trigger on the enables, in which case the circuit you think it should have synthesized to is impossible, as you can't drive the same register with two different clocks. You might try something like:

en_either <= en_up or en_down;

process (en_either, rst)
begin
  if rst = '1' then
    count <= (others => '0');
  elsif rising_edge(en_either) then
    if en_up = '1' then
      count <= count + 1;
    else
      count <= count - 1;
    end if;
  end if;
end process;

There may be better ways, but if you really can't have a clock, I suppose that will work. If the enables overlap in any way, of course, this may not work as intended.

As the error message indicates, your two-process version will not work because you're driving the same signal from two different processes. There may be ways to work around this, but it would be much more trouble than the 1-process version.

As David points out in the comments, this will not work properly unless your enables are bounce-free. The source of the enables isn't clear from your post.

\$\endgroup\$
  • 1
    \$\begingroup\$ The thought of putting both input signals through a gate didn't even cross my mind. Perhaps I could try an XOR as opposed to an OR for en_either? \$\endgroup\$ – krb686 Feb 15 '15 at 15:06
  • 1
    \$\begingroup\$ Both should work, although they will handle overlaps slightly differently of course. Then again, there will almost always be limitations, even with a clocked version. \$\endgroup\$ – fru1tbat Feb 15 '15 at 15:11
  • \$\begingroup\$ Ask him where he's getting debounce on EN_UP and EN_DOWN. \$\endgroup\$ – user8352 Feb 17 '15 at 8:22
  • \$\begingroup\$ I thought of that, but it didn't seem worth covering considering the level of detail in the spec provided. Probably should be mentioned, at least, I guess. \$\endgroup\$ – fru1tbat Feb 17 '15 at 13:46
3
\$\begingroup\$

You don't need a clock for this, but you need to better understand what you should do for every possible input given to your network.

The first approach is the best, so let's analyze it. You start by checking RESET and that's great, elsiffing whatever comes after is just how I would do it.

Now to the tricky part. You check if either EN_DOWN or EN_UP had a rising edge, check that the other signal is zero and act accordingly. That makes no sense to me, at least given the (little) specification you provide.

Since you are in a process you are sitting on edges already, i would just check what happened with the event thingy. Something like

count : PROCESS (RESET, EN_UP, EN_DOWN)
BEGIN
    if(RESET = '1') then
        countSignal <= x"0000";
    else
        if(EN_UP'EVENT and EN_UP = '1') then
            countSignal <= countSignal + 1;
        end if;
        if(EN_DOWN'EVENT and EN_DOWN = '1') then
            countSignal <= countSignal - 1;
        end if;
    end if;
END PROCESS;

This seems better to me and more adherent to what you ask.

For the record, an heuristic way to do this (so you understand you don't need a clock):

you have your 16 bit outpt register made with DFF, and two combinational networks that compute output - 1 and output + 1. these two networks are connected to a dual input mux, and the output register input is connected to the mux. the DFFs clocks are the or between count_up and count_down, while the mux control bit is one of them. When a pulse arrives the register is then refreshed with the correct value.

If you are not satisfied with the implementation you get after synthesys you can try to implement my latter idea and see if that works for you.

\$\endgroup\$
  • \$\begingroup\$ I was under the impression that rising_edge(EN_UP) essentially replaces if(EN_UP'EVENT and EN_UP = '1'), literally just a shorter way of saying the same thing. I have always used your suggested way in the past, but was recently taught that by a friend. As far as also checking the opposite signal is a 0, the logic was to prevent the overlap condition. Maybe splitting into separate if statements though could make a difference. Thanks, I will also try this. \$\endgroup\$ – krb686 Feb 15 '15 at 15:31
  • 1
    \$\begingroup\$ Unfortunately, this approach results in the compiler just disconnecting one of the EN signals, and then I get a bunch of warnings about parts being disconnected so they will be removed. \$\endgroup\$ – krb686 Feb 15 '15 at 17:10
1
\$\begingroup\$

It is possible to design a counter from purely combinatorial logic, if it is given two inputs rather than one, and the inputs change state in a well-defined pattern. For example, suppose one has two inputs P and Q, two eight-bit values X and Y, and computes them combinatorially as follows:

When P is high
  X=Y+1
Else
  X=X

When Q is high:
  Y=X+1
Else
  Y=Y

If P and Q alternately go high, then X and Y will count the number of times they have done so, provided that P and Q are never high simultaneously; if they do ever overlap, then the values of X and Y will be undefined.

Although flip flops have largely replaced the above style of circuitry, the two-phase clocking approach has historically been quite popular, especially since in NMOS technologies, given a minimum clock speed, one could use latching circuits that were much cheaper than flip flops. Consider:

schematic

simulate this circuit – Schematic created using CircuitLab

Each relay should simply be a single NFET, but I can't get those to simulate correctly, so I substituted a relay instead. This circuit implements a divide-by-two counter using five active transistors and three passive pull-ups. Implementing an edge-triggered flip flop would require more circuitry, so even though it's necessary to generate and distribute two clocks rather than one, the overall effect is a "win".

\$\endgroup\$
1
\$\begingroup\$

FPGAs really, really don't like to run without a clock. You get wildly unexpected behaviors. So you're much better off using a synchronous up/down counter with the up/down inputs sampled by a faster clock.

schematic

simulate this circuit – Schematic created using CircuitLab

The clock period should be no more than 1/3 the up or down pulse width.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.