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.
4 Answers 4
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.
-
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 anOR
foren_either
? \$\endgroup\$krb686– krb6862015年02月15日 15:06:30 +00:00Commented Feb 15, 2015 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– fru1tbat2015年02月15日 15:11:46 +00:00Commented Feb 15, 2015 at 15:11
-
\$\begingroup\$ Ask him where he's getting debounce on EN_UP and EN_DOWN. \$\endgroup\$user8352– user83522015年02月17日 08:22:10 +00:00Commented Feb 17, 2015 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– fru1tbat2015年02月17日 13:46:19 +00:00Commented Feb 17, 2015 at 13:46
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.
-
\$\begingroup\$ I was under the impression that
rising_edge(EN_UP)
essentially replacesif(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 a0
, 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– krb6862015年02月15日 15:31:36 +00:00Commented Feb 15, 2015 at 15:31 -
2\$\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– krb6862015年02月15日 17:10:59 +00:00Commented Feb 15, 2015 at 17:10
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".
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.