0
votes

I'm trying to write some VHDL code whose purpose is take some external input signals and redirect them some specific outputs. All signals are driven by their own external clock. I am in the process of designing and testing this, so the below code may not be entirely accurate.

Also, I try to latch or buffer the input signals on the input ports and on the output ports to ensure the signals have maximum propagation time inside the FPGA and on the external PCB to avoid timing violations. This is the only way I know to achieve this.

Now, on to the problem. This is basically a generic architecture with multiple clocks, so I'm using generate statements to generate different process blocks (mostly because my simulator refuses to compile the code otherwise). But then I have a problem where multiple processes are driving the same signals.

If I look at input_process_gen, I can either use generate statements, in which case I get multiple drivers. Or I can use loops, but then the simulator will complain about the rising edge clock statement. So I was wondering how to do this. Is using resolved signals a good idea? Will it work? I'm not entirely sure how to write one for these complicated signals, though. Still new at VHDL.

Maybe there's some better solution? There are probably other things that could be improved, and if that is the case, I'm open to hear about possible improvements. Thanks.

library ieee;
use ieee.std_logic_1164.all;

package generic_types is
    type signal_array is array (natural range <>, natural range <>) of std_logic;
    type port_array is array (natural range <>, natural range <>) of bit;
    type clk_array is array (natural range <>) of std_logic;
end package;

library ieee;
use work.generic_types.all;
use ieee.std_logic_1164.all;

entity generic_switch_fabric is
    generic (Inputs, Outputs, Bits: Integer);
    port
    (
        clk_in: in clk_array(Inputs - 1 downto 0);
        clk_out: out clk_array(Outputs - 1 downto 0);
        rst_n: in std_logic;
        input: in signal_array(Inputs - 1 downto 0, Bits - 1 downto 0);
        output: out signal_array(Outputs - 1 downto 0, Bits - 1 downto 0);
        port_switcher: in port_array(Inputs - 1 downto 0, Outputs - 1 downto 0)
    );
end entity;

architecture RTL of generic_switch_fabric is
    signal clocked_input: signal_array(Inputs - 1 downto 0, Bits - 1 downto 0);
    signal clocked_output: signal_array(Outputs - 1 downto 0, Bits - 1 downto 0);
    signal clk_out_int: clk_array(Outputs - 1 downto 0);
begin
    clk_process_gen: for input in 0 to Inputs - 1 generate
    clk_process_gen: for output in 0 to Outputs - 1 generate
        clk_process: process(clk_in, port_switcher)
        begin
            -- Propagate input clocks to output clocks
            if (port_switcher(input, output) = '1') then
                clk_out_int(output) <= clk_in(input);
            else
                clk_out_int(output) <= 'Z';
            end if;
        end process;
    end generate;
    end generate;

    clk_process_fwrd: for output in 0 to Outputs - 1 generate
        clk_process: process(clk_out_int)
        begin
            -- Propagate input clocks to output clocks
            clk_out(output) <= clk_out_int(output);
        end process;
    end generate;

    input_process_gen: for input_idx in 0 to Inputs - 1 generate
        input_process: process(clk_in)
        begin
            -- Register on inputs
    --      for input_idx in 0 to Inputs - 1 loop
                if (rising_edge(clk_in(input_idx))) then
                    for output_idx in Bits - 1 downto 0 loop
                        clocked_input(input_idx, output_idx) <= input(input_idx, output_idx);
                    end loop;
                end if;
        --  end loop;
        end process;
    end generate;

    output_process_gen: for output_idx in 0 to Outputs - 1 generate
        output_process: process(clk_out_int)
        begin
            -- Register on outputs
            if (rising_edge(clk_out_int(output_idx))) then
                for input_idx in Bits - 1 downto 0 loop
                    output(output_idx, input_idx) <= clocked_output(output_idx, input_idx);
                end loop;
            end if;
        end process;
    end generate;

    -- rst_process: process(rst_n)
    -- begin
        -- if (rst_n = '0') then
            -- clocked_output <= (others => (others => '0'));
        -- else
            -- clocked_output <= (others => (others => 'Z'));
        -- end if;
    -- end process;

    switcher_generation: for i in 0 to Inputs - 1 generate
        switch_process: process(clocked_input, port_switcher) is
        begin
            clocked_output <= (others => (others => 'Z'));

            -- ...For every output to port to output it to...
            for j in 0 to Outputs - 1 loop

                -- ...If input it supposed to be output to this port...
                if (port_switcher(i, j) = '1') then

                    -- ...Copy all the bits from the input to the output...
                    for k in 0 to Bits - 1 loop
                        clocked_output(j, k) <= clocked_input(i, k);
                    end loop;
                end if;
            end loop;
        end process;
    end generate;
end architecture RTL;
1

1 Answers

0
votes
clk_process_gen: for input in 0 to Inputs - 1 generate
clk_process_gen: for output in 0 to Outputs - 1 generate
    clk_process: process(clk_in, port_switcher)
    begin
        -- Propagate input clocks to output clocks
        if (port_switcher(input, output) = '1') then
            clk_out_int(output) <= clk_in(input);
        else
            clk_out_int(output) <= 'Z';
        end if;
    end process;
end generate;
end generate;

This will generate input signals all connected to clk_int(output). Tristate driver for internal logic is not supported on modern FPGA, so this is bound to fail with "multiple drivers" error.

You need to use a multiplexer approach instead:

clk_process_gen: for output in 0 to Outputs - 1 generate
    clk_process: process(clk_in, port_switcher)
    begin
        -- Propagate input clocks to output clocks
        clk_out_int(output) <= clk_in(port_switcher(output));
    end process;
end generate;

This would require a change to the defination of port_array: type port_array is array (natural range <>) of natural;

Note that muxing clocks is not recommended without clock-dedicated muxer, which doesn't support more than 2 clocks AFAIK. Thus, you will have skew issues on your output, as well as potential glitches when you change the configuration.