Electrical – How to convert data before sending it to FIFO [Xillybus – VHDL]

fpgavhdl

I connected my own FIFO to xillydemo. More precisely, xillydemo receives some data, it has to convert the data and the forward the data to FIFO. in turn the FIFO should send data back to xillydemo. What I want to do is to convert (in xillydemo.vhd) one every eight characters from upper case to lower case (and viceversa) and then send all of them to STD_FIFO. (E.g: input string in xillydemo.vhd is "HelloMyNameIsJohnAndIWorkInUK" then the string to be sent to STD_FIFO should be "helloMyNAmeIsJohNAndIWorKInUK").

To do this, I defined 4 signals wr_en, full, din and counter in xillydemo.vhd. wr_en, full and din are connected to user_w_write_8_wren, user_w_write_8_full and user_w_write_8_data xillydemosignals respectively. The counter is used to count from 0 to 7 in order to convert only the first char. The problem of my code is that it does not output anything. E.g., if the xillydemo input string is "HelloMyNameIsJohnAndIWorkInUK", the string sent back from STD_FIFO to xillydemo is empty.

NOTE: the problem is not similar to this question because the user suggested to go in this other question. The difference between this question and the two linked questions is that here I want to send to FIFO the swapped characters and not convert them into FIFO logic.

Here xillydmeo.vhd:

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.numeric_std.all;

entity xillydemo is
  port (
     PCIE_PERST_B_LS : IN std_logic;
     PCIE_REFCLK_N : IN std_logic;
     PCIE_REFCLK_P : IN std_logic;
     PCIE_RX_N : IN std_logic_vector(3 DOWNTO 0);
     PCIE_RX_P : IN std_logic_vector(3 DOWNTO 0);
     GPIO_LED : OUT std_logic_vector(3 DOWNTO 0);
     PCIE_TX_N : OUT std_logic_vector(3 DOWNTO 0);
     PCIE_TX_P : OUT std_logic_vector(3 DOWNTO 0));
end xillydemo;

architecture sample_arch of xillydemo is

  component xillybus
    port (
      PCIE_PERST_B_LS : IN std_logic;
      PCIE_REFCLK_N : IN std_logic;
      PCIE_REFCLK_P : IN std_logic;
      PCIE_RX_N : IN std_logic_vector(3 DOWNTO 0);
      PCIE_RX_P : IN std_logic_vector(3 DOWNTO 0);
      GPIO_LED : OUT std_logic_vector(3 DOWNTO 0);
      PCIE_TX_N : OUT std_logic_vector(3 DOWNTO 0);
      PCIE_TX_P : OUT std_logic_vector(3 DOWNTO 0);
      bus_clk : OUT std_logic;
      quiesce : OUT std_logic;

      user_r_read_8_rden : OUT std_logic;
      user_r_read_8_empty : IN std_logic;
      user_r_read_8_data : IN std_logic_vector(7 DOWNTO 0);
      user_r_read_8_eof : IN std_logic;
      user_r_read_8_open : OUT std_logic;
      user_w_write_8_wren : OUT std_logic;
      user_w_write_8_full : IN std_logic;
      user_w_write_8_data : OUT std_logic_vector(7 DOWNTO 0);
      user_w_write_8_open : OUT std_logic);
  end component;

  component STD_FIFO
    port (
      CLK: IN std_logic;
      RST: IN std_logic;
      DataIn: IN std_logic_VECTOR(7 downto 0);
      WriteEn: IN std_logic;
      ReadEn: IN std_logic;
      DataOut: OUT std_logic_VECTOR(7 downto 0);
      Full: OUT std_logic;
      Empty: OUT std_logic);
  end component;

  signal bus_clk :  std_logic;
  signal quiesce : std_logic;
  signal reset_8 : std_logic;

  signal user_r_read_8_rden  :  std_logic;
  signal user_r_read_8_empty :  std_logic;
  signal user_r_read_8_data  :  std_logic_vector(7 DOWNTO 0);
  signal user_r_read_8_eof   :  std_logic;
  signal user_r_read_8_open  :  std_logic;
  signal user_w_write_8_wren :  std_logic;
  signal user_w_write_8_full :  std_logic;
  signal user_w_write_8_data :  std_logic_vector(7 DOWNTO 0);
  signal user_w_write_8_open :  std_logic;

  signal wr_en               :  std_logic := '0';
  signal din                 :  std_logic_vector(user_w_write_8_data'range) := (others => '0');
  signal counter             :  integer := 0;
  signal full                :  std_logic := '0';
begin
  xillybus_ins : xillybus
    port map (
      -- Ports related to /dev/xillybus_read_8
      -- FPGA to CPU signals:
      user_r_read_8_rden => user_r_read_8_rden,
      user_r_read_8_empty => user_r_read_8_empty,
      user_r_read_8_data => user_r_read_8_data,
      user_r_read_8_eof => user_r_read_8_eof,
      user_r_read_8_open => user_r_read_8_open,

      -- Ports related to /dev/xillybus_write_8
      -- CPU to FPGA signals:
      user_w_write_8_wren => user_w_write_8_wren,
      user_w_write_8_full => user_w_write_8_full,
      user_w_write_8_data => user_w_write_8_data,
      user_w_write_8_open => user_w_write_8_open,

      -- General signals
      PCIE_PERST_B_LS => PCIE_PERST_B_LS,
      PCIE_REFCLK_N => PCIE_REFCLK_N,
      PCIE_REFCLK_P => PCIE_REFCLK_P,
      PCIE_RX_N => PCIE_RX_N,
      PCIE_RX_P => PCIE_RX_P,
      GPIO_LED => GPIO_LED,
      PCIE_TX_N => PCIE_TX_N,
      PCIE_TX_P => PCIE_TX_P,
      bus_clk => bus_clk,
      quiesce => quiesce
   );

  process (bus_clk)

  begin 
        if (bus_clk'event and bus_clk = '1') then
            if (reset_8 = '1') then 
                counter <= 0;
             else 
                wr_en <= user_w_write_8_wren;
                full <= user_w_write_8_full;

                if (user_w_write_8_wren='1') then
                    din <= user_w_write_8_data;

                    if counter=0 then
                        --From upper case to lower case
                        if (user_w_write_8_data="01000001") then --A
                            din(5) <= not user_w_write_8_data(5);
                                  elsif (user_w_write_8_data="01000010") then --B
                                      din(5) <= not user_w_write_8_data(5);
                                  elsif (user_w_write_8_data="01000011") then --C
                                      din(5) <= not user_w_write_8_data(5);
                                  elsif (user_w_write_8_data="01000100") then --D
                                      din(5) <= not user_w_write_8_data(5);
                                  elsif (user_w_write_8_data="01000101") then --E
                                      din(5) <= not user_w_write_8_data(5);
                                  elsif (user_w_write_8_data="01000110") then --F
                                      din(5) <= not user_w_write_8_data(5);
                                  elsif (user_w_write_8_data="01000111") then --G
                                      din(5) <= not user_w_write_8_data(5);
                                  elsif (user_w_write_8_data="01001000") then --H
                                      din(5) <= not user_w_write_8_data(5);
                                  elsif (user_w_write_8_data="01001001") then --I
                                      din(5) <= not user_w_write_8_data(5);
                                  elsif (user_w_write_8_data="01001010") then --J
                                      din(5) <= not user_w_write_8_data(5);
                                  elsif (user_w_write_8_data="01001011") then --K
                                      din(5) <= not user_w_write_8_data(5);
                                  elsif (user_w_write_8_data="01001100") then --L
                                      din(5) <= not user_w_write_8_data(5);
                                  elsif (user_w_write_8_data="01001101") then --M 
                                      din(5) <= not user_w_write_8_data(5);
                                  elsif (user_w_write_8_data="01001110") then --N 
                                      din(5) <= not user_w_write_8_data(5);
                                  elsif (user_w_write_8_data="01001111") then --O
                                      din(5) <= not user_w_write_8_data(5);
                                  elsif (user_w_write_8_data="01010000") then --P
                                      din(5) <= not user_w_write_8_data(5);
                                  elsif (user_w_write_8_data="01010001") then --Q
                                      din(5) <= not user_w_write_8_data(5);
                                  elsif (user_w_write_8_data="01010010") then --R
                                      din(5) <= not user_w_write_8_data(5);
                                  elsif (user_w_write_8_data="01010011") then --S
                                      din(5) <= not user_w_write_8_data(5);
                                  elsif (user_w_write_8_data="01010100") then --T
                                      din(5) <= not user_w_write_8_data(5);
                                  elsif (user_w_write_8_data="01010101") then --U
                                      din(5) <= not user_w_write_8_data(5);
                                  elsif (user_w_write_8_data="01010110") then --V
                                      din(5) <= not user_w_write_8_data(5);
                                  elsif (user_w_write_8_data="01010111") then --W
                                      din(5) <= not user_w_write_8_data(5);
                                  elsif (user_w_write_8_data="01011000") then --X
                                      din(5) <= not user_w_write_8_data(5);
                                  elsif (user_w_write_8_data="01011001") then --Y
                                      din(5) <= not user_w_write_8_data(5);
                                  elsif (user_w_write_8_data="01011010") then --Z
                                      din(5) <= not user_w_write_8_data(5);

                                  --From lower case to upper case
                                  elsif (user_w_write_8_data="01100001") then --a
                                      din(5) <= not user_w_write_8_data(5);
                                  elsif (user_w_write_8_data="01100010") then --b
                                      din(5) <= not user_w_write_8_data(5);
                                  elsif (user_w_write_8_data="01100011") then --c
                                      din(5) <= not user_w_write_8_data(5);
                                  elsif (user_w_write_8_data="01100100") then --d
                                      din(5) <= not user_w_write_8_data(5);
                                  elsif (user_w_write_8_data="01100101") then --e
                                      din(5) <= not user_w_write_8_data(5);
                                  elsif (user_w_write_8_data="01100110") then --f
                                      din(5) <= not user_w_write_8_data(5);
                                  elsif (user_w_write_8_data="01100111") then --g
                                      din(5) <= not user_w_write_8_data(5);
                                  elsif (user_w_write_8_data="01101000") then --h
                                      din(5) <= not user_w_write_8_data(5);
                                  elsif (user_w_write_8_data="01101001") then --i
                                      din(5) <= not user_w_write_8_data(5);
                                  elsif (user_w_write_8_data="01101010") then --j
                                      din(5) <= not user_w_write_8_data(5);
                                  elsif (user_w_write_8_data="01101011") then --k
                                      din(5) <= not user_w_write_8_data(5);
                                  elsif (user_w_write_8_data="01101100") then --l
                                      din(5) <= not user_w_write_8_data(5);
                                  elsif (user_w_write_8_data="01101101") then --m
                                      din(5) <= not user_w_write_8_data(5);
                                  elsif (user_w_write_8_data="01101110") then --n
                                      din(5) <= not user_w_write_8_data(5);
                                  elsif (user_w_write_8_data="01101111") then --o 
                                      din(5) <= not user_w_write_8_data(5);
                                  elsif (user_w_write_8_data="01110000") then --p 
                                      din(5) <= not user_w_write_8_data(5);
                                  elsif (user_w_write_8_data="01110001") then --q
                                      din(5) <= not user_w_write_8_data(5);
                                  elsif (user_w_write_8_data="01110010") then --r
                                      din(5) <= not user_w_write_8_data(5);
                                  elsif (user_w_write_8_data="01110011") then --s
                                      din(5) <= not user_w_write_8_data(5);
                                  elsif (user_w_write_8_data="01110100") then --t
                                      din(5) <= not user_w_write_8_data(5);
                                  elsif (user_w_write_8_data="01110101") then --u
                                      din(5) <= not user_w_write_8_data(5);
                                  elsif (user_w_write_8_data="01110110") then --v
                                      din(5) <= not user_w_write_8_data(5);
                                  elsif (user_w_write_8_data="01110111") then --w
                                      din(5) <= not user_w_write_8_data(5);
                                  elsif (user_w_write_8_data="01111000") then --x
                                      din(5) <= not user_w_write_8_data(5);
                                  elsif (user_w_write_8_data="01111001") then --y
                                      din(5) <= not user_w_write_8_data(5);
                                  elsif (user_w_write_8_data="01111010") then --z
                                      din(5) <= not user_w_write_8_data(5);
                                  end if;
                              end if;

                              if (counter=7) then
                                  counter <= 0;
                              else
                                  counter <= counter+1;
                              end if; 
                          end if;
                      end if; 
                end if;
  end process;

  my_fifo : STD_FIFO
    port map(
          CLK       => bus_clk,
          RST       => reset_8,
          DataIn    => din,
          WriteEn   => wr_en,
          ReadEn    => user_r_read_8_rden,
          DataOut   => user_r_read_8_data,
          Full      => full,
          Empty     => user_r_read_8_empty
      );

    reset_8 <= not (user_w_write_8_open or user_r_read_8_open);
    user_r_read_8_eof <= user_r_read_8_empty and not(user_w_write_8_open);

end sample_arch;

Here FIFO code

library IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.NUMERIC_STD.ALL;

entity STD_FIFO is
    Generic (
        constant DATA_WIDTH  : positive := 8;
        constant FIFO_DEPTH : positive := 3
    );
    Port ( 
        CLK     : in  STD_LOGIC;
        RST     : in  STD_LOGIC;
        WriteEn : in  STD_LOGIC;
        DataIn  : in  STD_LOGIC_VECTOR (DATA_WIDTH - 1 downto 0);
        ReadEn  : in  STD_LOGIC;
        DataOut : out STD_LOGIC_VECTOR (DATA_WIDTH - 1 downto 0);
        Empty   : out STD_LOGIC;
        Full    : out STD_LOGIC
    );
end STD_FIFO;

architecture Behavioral of STD_FIFO is

begin

    -- Memory Pointer Process
    fifo_proc : process (CLK)
        type FIFO_Memory is array (0 to FIFO_DEPTH - 1) of STD_LOGIC_VECTOR (DATA_WIDTH - 1 downto 0);
        variable Memory : FIFO_Memory;

        variable Head : natural range 0 to FIFO_DEPTH - 1;
        variable Tail : natural range 0 to FIFO_DEPTH - 1;

        variable Looped : boolean;
    begin
        if rising_edge(CLK) then
            if RST = '1' then
                Head := 0;
                Tail := 0;

                Looped := false;

                Full  <= '0';
                Empty <= '1';
            else
                if (ReadEn = '1') then
                    if ((Looped = true) or (Head /= Tail)) then
                        -- Update data output
                        DataOut <= Memory(Tail);

                        -- Update Tail pointer as needed
                        if (Tail = FIFO_DEPTH - 1) then
                            Tail := 0;

                            Looped := false;
                        else
                            Tail := Tail + 1;
                        end if;


                    end if;
                end if;

                if (WriteEn = '1') then
                    if ((Looped = false) or (Head /= Tail)) then
                        -- Write Data to Memory
                        Memory(Head) := DataIn;

                        -- Increment Head pointer as needed
                        if (Head = FIFO_DEPTH - 1) then
                            Head := 0;

                            Looped := true;
                        else
                            Head := Head + 1;
                        end if;
                    end if;
                end if;

                -- Update Empty and Full flags
                if (Head = Tail) then
                    if Looped then
                        Full <= '1';
                    else
                        Empty <= '1';
                    end if;
                else
                    Empty   <= '0';
                    Full    <= '0';
                end if;
            end if;
        end if;
    end process;

end Behavioral;

Best Answer

A simple solution would be to use a Mealy Machine. Here, you would only intercept the data user_w_write_8_data which will be written to the FIFO. All control signals associated with the write side should be left as in the original XillyBus demo. Thus, the instantiation of your STD_FIFO will be:

  my_fifo : STD_FIFO
    port map(
          CLK       => bus_clk,
          RST       => reset_8,
          DataIn    => din,                 -- modified data to write
          WriteEn   => user_w_write_8_wren, -- as in original demo!
          ReadEn    => user_r_read_8_rden,
          DataOut   => user_r_read_8_data,
          Full      => user_w_write_8_full, -- as in original demo!
          Empty     => user_r_read_8_empty
      );

Instead of STD_FIFO you can also use the component fifo_8x2048 of the XillyBus demo.

The Mealy Machine will then have a counter which is incremented with every write. Whenever the counter state is 0, the write data user_w_write_8_data is modified and assigned to signal din which is connected to the FIFO. In all other cases, the original value of user_w_write_8_data is assigned to din.

Thus, the code of the clocked process would look like this:

  process (bus_clk)
  begin 
        if (bus_clk'event and bus_clk = '1') then
            if (reset_8 = '1') then 
                counter <= 0;
             elsif (user_w_write_8_wren='1') then
                if counter = 7 then counter <= 0;
                else                counter <= counter + 1;
                end if;
             end if;
        end if;
  end process;

The Mealy Machine will have another process which defines the output for the current cycle based on the current state of the counter (or any other state variable). You must list all signals in any expression in the process sensitivity list. You must also assign a value to every output in every control path, otherwise you will get unintended latches. The latter is ensured by assigning a default value at the beginning of the process and overwrite it later on. Always the last assignment (before a wait) wins.

  process(counter, user_w_write_8_data)
  begin
     -- This is the default assignment which might be overriden below.
     din <= user_w_write_8_data;

     if counter=0 then
        --From upper case to lower case
        if (user_w_write_8_data="01000001") then --A
            din(5) <= not user_w_write_8_data(5);
        elsif (user_w_write_8_data="01000010") then --B
            --
            -- And so on
            --
        end if;
     end if;
  end process;