2
\$\begingroup\$

I'm attempting to create synthesisable VHDL that will demultiplex a one-bit continuous signal stream to one of many outputs. The outputs that aren't being sent this stream should be set to '0'. See image below for an idea of what I'm trying to achieve.

Demux Diagram

The code I've written to create this functionality is:

send_s         <= (line_select_s => prbs_i(0), others => '0');

where 'prbs_i(0)' is the signal stream.

Unfortunately this is unsynthesisable in Vivado, giving the error:

[Synth 8-211] could not evaluate expression: aggregate choice expression

Is there a proper way to do this? The VHDL simulates fine but will not synthesise.

\$\endgroup\$
3
\$\begingroup\$

The problem with your code is that an assignment of the form:

a <= (3 => '0', others => '1');

must use constants for the offsets being assigned (in this case, 3).

If you need the offset being set to vary, you have to split it into two assignments. Note that this will only work inside a process; with a pair of concurrent assignments, you would encounter a multiple driver problem.

process (line_select_s, prbs_i)
begin
  send_s <= (others => '0');
  send_s(line_select_s) <= prbs_i(0);
end process;

This works because although we start by assigning '0' to the whole vector, the last assignment to a particular signal in a process will take priority.

An alternative is to use a loop:

process (line_select_s, prbs_i)
begin
  send_s <= (others => '0');
  for i in send_s'range loop
    if (i = line_select_s) then
      send_s(i) <= prbs_i(0);
    end if;
  end loop;
end process;

This has the advantage that if your select signal can represent an offset larger than the width of your target vector, no error will be produced in simulation. An example scenario would be a 3-bit select signal, but a target vector with only 5 elements; the first method would produce an error if the select signal represented 6, 7, or 8, but the second would not.

As a side note, you may want to make a process like this synchronous if you want to get the best performance (in terms of maximum operating frequency) out of your design.

\$\endgroup\$
  • 2
    \$\begingroup\$ Just to expand why you can't simplify the loop to send_s(line_select_s) <= prbs_i(0); : remember this process has to generate hardware to allow any output to carry the signal (hence the loop), and only drive the selected one (hence the if). The loop is effectively unrolled by synthesis, generating a set of drivers that operate in parallel, one for each output. \$\endgroup\$ – Brian Drummond Jan 9 '18 at 14:25
  • \$\begingroup\$ Great, thanks @scary_jeff! That makes sense. Forgot to mention - I did already have this in a synchronous process, so your idea was simple to add in to my existing code. @BrianDrummond, I had suspected as much however was disappointed that the synthesiser / VHDL standard wasn't 'smart enough' to allow the one-line approach. \$\endgroup\$ – BenAdamson Jan 9 '18 at 14:31
  • \$\begingroup\$ That's the difference between simulation (where it should work) and synthesis generating hardware. Synth tools have got a lot smarter but they still basically operate by seeing design patterns (like this loop) and transforming them. \$\endgroup\$ – Brian Drummond Jan 9 '18 at 14:35
  • 1
    \$\begingroup\$ @BrianDrummond you've made me doubt myself, I don't see why send_s <= (others => '0'); send_s(line_select_s) <= prbs_i(0); wouldn't work? \$\endgroup\$ – scary_jeff Jan 9 '18 at 14:41
  • \$\begingroup\$ Edited answer to simplify. The loop wasn't required. \$\endgroup\$ – scary_jeff Jan 9 '18 at 15:01
1
\$\begingroup\$

Many ways are there. One simple way of doing is, by dataflow model:

with line_select_s select
send_s <= (send_s & "0000") when "000",
        ('0' & send_s & "000") when "001",
        ("00" & send_s & "00") when "010",
        ("000" & send_s & '0') when "011";
        ("0000" & send_s) when "100";
         "00000" when others;
\$\endgroup\$
  • \$\begingroup\$ This would work however isn't really usable when you have more than a few output lines. In my case I have over 30. \$\endgroup\$ – BenAdamson Jan 9 '18 at 14:44
  • 1
    \$\begingroup\$ This code segment would be longer for 30 lines. But remember that code size and the synthesised hardware size has no relation with each other. \$\endgroup\$ – Mitu Raj Jan 9 '18 at 15:00
  • 1
    \$\begingroup\$ But you code is not maintainable. A demux can be described in 3 lines: for-generate statement and a simple AND gate! The second input of the AND-gate is the onehot encoded version if the select signal. The onehot encoding can be done in a function. This scales to any size bit and keeps a maintainable/readable code. \$\endgroup\$ – Paebbels Jan 10 '18 at 10:51
  • \$\begingroup\$ Maintainibility. Okay agreed. But outcome is still the same hardware. Doesn't mean my answer is wrong or so to hit a downvote. \$\endgroup\$ – Mitu Raj Jan 10 '18 at 12:08

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.