2017-03-15 6 views
0

레코드 유형이 입/출력되는 FIFO를 가정하면 실제 FIFO에서 FIFO 래퍼 및 std_logic_vector의 입력 및 출력에서 ​​레코드 유형 간의 매핑을 처리하는 간단한 방법이 있습니까?VHDL/FPGA의 FIFO에 레코드를 쓰거나 읽는 간단한 방법이 있습니까?

+0

필자는 이것을 올바르게 이해한다고 가정하고 FIFO에 대한 입/출력 레코드를 사용하기로 결정했습니다. 레코드를 입력으로 사용하고 std_logic_vector를 반환하는 함수를 사용하지 마십시오. 그 반대의 경우도 마찬가지입니다. –

+0

가정은 정확합니다. 이 함수들이 단순화되었거나 예제 응답에 표시된 것보다 작성하기 쉬운 오류가 적은 예제가 있습니까? – FritzDC

+0

나는 오류가 덜 발생하는 능력에 대해 확신하지 못하는 예제를 추가 할 것이다 - 당신이 더 잘 판단 할 수있을 것 같다. –

답변

0

내가 지금까지 가지고 올 수 있었던 가장 간단한 방법은 다음과 같다 : 첫째

일정 범위 선언 정돈하는 기능 패키지 :

library ieee; 
use ieee.std_logic_1164.all; 
package Fun_pck is 
    function fLenAtTopOf(a : natural; b: std_logic_vector) return natural; 
    function fTopOf(b : std_logic_vector) return natural; 
end package Fun_pck; 
package body Fun_pck is 
    function fLenAtTopOf(a : natural; b: std_logic_vector) return natural is 
    begin 
    return a+b'left; 
    end function fLenAtTopOf; 
    function fTopOf(b: std_logic_vector) return natural is 
    begin 
    return b'left+1; 
    end function fTopOf; 
end package body Fun_pck; 

그런 다음 두 개의 패키지 포함

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

package ExampleFifo_pck_private is 

-- This package is 'private', i.e. only meant to be seen by the package and 
-- entity in this file. This is so that the elements will not have a name 
-- clash. As they are top-level constants that would be a likely problem. 
-- Fifo element constants. 
    type width_array is array (integer range <>) of integer; 
    constant cElementWidths : width_array(0 to 2) := (4, 8, 1); 

    constant cFifoElement0 : std_logic_vector(cElementWidths(0)-1 downto 0) := (others => '0'); 
    constant cFifoElement1 : std_logic_vector(
    fLenAtTopOf(cElementWidths(1), cFifoElement0) downto 
    fTopOf(cFifoElement0)) := (others => '0'); 
    constant cFifoElement2 : std_logic_vector(
    fLenAtTopOf(cElementWidths(2), cFifoElement1) downto 
    fTopOf(cFifoElement1)) := (others => '0'); 

-- General Form: 
--constant cFifoElementN : std_logic_vector(
-- fLenAtTopOf(cElementWidths(N), cFifoElement[N-1]) downto 
-- fTopOf(cFifoElement[N-1])) := (others => '0'); 
end package ExampleFifo_pck_private; 

library ieee; 
use ieee.std_logic_1164.all; 
use work.Fun_pck.all; 
use work.ExampleFifo_pck_private.all; 

-- Fifo item type 
    type tExampleFifoData is record 
    A : std_logic_vector(cFifoElement0'length-1 downto 0); 
    B : std_logic_vector(cFifoElement1'length-1 downto 0); 
    C : std_logic_vector(cFifoElement2'length-1 downto 0); 
    end record tExampleFifoData; 

-- Reset constant 
    constant cResetExampleFifoData : tExampleFifoData := (
    A => cFifoElement0, 
    B => cFifoElement1, 
    C => cFifoElement2 
    ); 
-- Length Constant 
    constant cExampleFifoWidth : integer := fTopOf(cFifoElement2); 
    -- Data array type 
    type tExampleFifoData_Array is array (natural range<>) of tExampleFifoData; 
end package ExampleFifo_pck; 

마지막 개체/아키텍처 쌍이 경우, 자일링스 XPM을 FIFO 모듈을 래핑 : FIFO에 대한 도우미 정의

library ieee; 
    use ieee.std_logic_1164.all; 
    use work.ExampleFifo_pck.all; 
    use work.ExampleFifo_pck_private.all; 

    library xpm; 
    use xpm.vcomponents.all; 

    entity ExampleFifo is 
     port (
     iWrClk  : in std_logic; 
     iRst  : in std_logic; 
     iWrEn  : in std_logic; 
     iWrData  : in tExampleFifoData; 
     oWrFull  : out std_logic; 
     oWrProgFull : out std_logic; 
     iRdClk  : in std_logic; 
     iRdEn  : in std_logic; 
     oRdData  : out tExampleFifoData; 
     oRdEmpty : out std_logic 
     ); 
    end entity ExampleFifo; 

    architecture RTL of ExampleFifo is 

    -- Internal vector signals 
     signal sWrData : std_logic_vector(cExampleFifoWidth-1 downto 0) := (others => '0'); 
     signal sRdData : std_logic_vector(cExampleFifoWidth-1 downto 0) := (others => '0'); 

    begin 

     sWrData(cFifoElement0'range) <= iWrData.A; 
     sWrData(cFifoElement1'range) <= iWrData.B; 
     sWrData(cFifoElement2'range) <= iWrData.C; 

     oRdData.A <= sRdData(cFifoElement0'range); 
     oRdData.B <= sRdData(cFifoElement1'range); 
     oRdData.C <= sRdData(cFifoElement2'range); 

     x_fifo : xpm_fifo_async 
     generic map (
      -- check: 
      FIFO_MEMORY_TYPE => "distributed", --string; "auto", "block", or "distributed"; 
      ECC_MODE   => "no_ecc",  --string; "no_ecc" or "en_ecc"; 
      -- check: 
      RELATED_CLOCKS  => 0,    --positive integer; 0 or 1 
      -- check: 
      FIFO_WRITE_DEPTH => 32,    --positive integer 
      -- modify: 
      WRITE_DATA_WIDTH => cExampleFifoWidth, --positive integer 
      WR_DATA_COUNT_WIDTH => 1,    --positive integer 
      -- check: 
      PROG_FULL_THRESH => 27,    --positive integer 
      FULL_RESET_VALUE => 0,    --positive integer; 0 or 1; 
      read_mode   => "fwft",   --string; "std" or "fwft"; 
      FIFO_READ_LATENCY => 0,    --positive integer; 
      -- modify: 
      READ_DATA_WIDTH  => cExampleFifoWidth,   --positive integer 
      RD_DATA_COUNT_WIDTH => 1,    --positive integer 
      PROG_EMPTY_THRESH => 10,    --positive integer 
      DOUT_RESET_VALUE => "0",   --string 
      CDC_SYNC_STAGES  => 2,    --positive integer 
      WAKEUP_TIME   => 0    --positive integer; 0 or 2; 
     ) 
     port map (
      sleep   => '0', 
      rst   => iRst, 
      wr_clk  => iWrClk, 
      wr_en   => iWrEn, 
      din   => sWrData, 
      full   => oWrFull, 
      overflow  => open, 
      wr_rst_busy => open, 
      rd_clk  => iRdClk, 
      rd_en   => iRdEn, 
      dout   => sRdData, 
      empty   => oRdEmpty, 
      underflow  => open, 
      rd_rst_busy => open, 
      prog_full  => oWrProgFull, 
      wr_data_count => open, 
      prog_empty => open, 
      rd_data_count => open, 
      injectsbiterr => '0', 
      injectdbiterr => '0', 
      sbiterr  => open, 
      dbiterr  => open 
     ); 
    end architecture RTL; 

이것은 약간 문제지만, fifo를 선언하는 것은 꽤 관리하기 쉽습니다. 각기 다른 fifo는 여전히 자신의 패키지와 엔티티 버전을 필요로합니다. 당연히 그들은 단일 파일에있을 수 있습니다.

이 문제가 후, ​​FIFO의 실제 사용은 매우 간단합니다 :

간단한 것으로 만들어
library ieee; 
use ieee.std_logic_1164.all; 
use work.ExampleFifo_pck.all; 

entity tb is 
end entity tb; 

architecture sim of tb is 
    signal iWrClk  : std_logic := '1'; 
    signal iRst  : std_logic := '0'; 
    signal sWrEn  : std_logic := '0'; 
    signal sWrData  : tExampleFifoData; 
    signal sWrFull  : std_logic; 
    signal sWrProgFull : std_logic; 
    signal iRdClk  : std_logic := '1'; 
    signal sRdEn  : std_logic := '0'; 
    signal sRdData  : tExampleFifoData; 
    signal sRdEmpty : std_logic; 

    signal sTestIn : tExampleFifoData  := cResetExampleFifoData; 
    signal sTestOut : tExampleFifoData; 
    constant tests : tExampleFifoData_Array(0 to 1) := 
    (0 => (x"E", x"A7", "1"), 1 => (x"7", x"AC", "0")); 
begin 

    iWrClk <= not iWrClk after 5 ns; 
    iRdClk <= not iRdClk after 7.2 ns; 

    ExFifo : entity work.ExampleFifo 
    port map (
     iWrClk  => iWrClk, 
     iRst  => iRst, 
     iWrEn  => sWrEn, 
     iWrData  => sTestIn, 
     oWrFull  => sWrFull, 
     oWrProgFull => sWrProgFull, 
     iRdClk  => iRdClk, 
     iRdEn  => sRdEn, 
     oRdData  => sTestOut, 
     oRdEmpty => sRdEmpty 
    ); 

    wr : process is 
    begin 
    iRst <= '1'; 
    for i in 0 to 5 loop 
     wait until rising_edge(iWrClk);  
    end loop; 
    iRst <= '0'; 
    wait for 150 ns; 
    for i in 0 to 1 loop 
     wait for 15 ns; 
     wait until rising_edge(iWrClk); 
     sTestIn <= tests(i); 
     sWrEn <= '1'; 
     wait until rising_edge(iWrClk); 
     sWrEn <= '0'; 
     wait until rising_edge(iWrClk); 
    end loop; 
    wait; 
    end process wr; 

    rd : process is 
    begin 
    wait until rising_edge(iRdClk); 
    sRdEn <= '0'; 
    if(sRdEmpty = '0' ans sRdEn <= '0') then 
     sRdEn <= '1'; 
    end if; 
    end process rd; 

end architecture sim; 
0

...

-- items within fifo 
constant c_items : integer := 8; 
constant c_width : integer := 
(-- ADD NEW ITEMS HERE 
    c_CWidth + 
    c_BWidth + 
    c_AWidth 
); 
type t_intVector is array (natural range <>) of integer; 
constant c_start : t_intVector(c_items downto 0) := 
(-- INSERT/MODIFY FOR NEW ITEMS 
    0+c_AWidth+c_BWidth+c_CWidth, -- end 
    0+c_AWidth+c_BWidth,   -- C 
    0+c_AWidth,     -- B 
    0        -- A 
); 

-- MODIFY FOR ADDITIONAL ITEMS 
procedure f_writeToFifo(
    signal o_f : out std_logic_vector; 
      i_A :  unsigned; 
      i_B :  unsigned; 
      i_C :  unsigned) is 
begin 
    o_f <= i_C & 
      i_B & 
      i_A; 
end procedure f_writeToFifo; 

type t_data is record 
    A : unsigned(c_AWidth-1 downto 0); 
    B : unsigned(c_BWidth-1 downto 0); 
    C : unsigned(c_CWidth-1 downto 0); 
end record; 

function f_readA(i_f : std_logic_vector) return unsigned is begin return unsigned(i_f(c_start(3)-1 downto c_start(2))); end function f_readA; 
function f_readB(i_f : std_logic_vector) return unsigned is begin return unsigned(i_f(c_start(2)-1 downto c_start(1))); end function f_readB; 
function f_readC(i_f : std_logic_vector) return unsigned is begin return unsigned(i_f(c_start(1)-1 downto c_start(0))); end function f_readC; 
function f_read (i_f : std_logic_vector) return t_data is begin 
    return (C => f_readC(i_f), 
      B => f_readB(i_f), 
      A => f_readA(i_f)); 
end function f_read; 

목록/위치/아이템 생성을 무시합니다. 절차/기록/기능은 제가 강조하고자했던 것입니다.

1

제시된대로 패키지의 대화를 숨길 수 있습니다. 따라서 FIFO 인터페이스와 레코드 사이의 2 가지 기능이 있습니다.

Rob Gaddi (VHDL 용 IEEE WG 부회장)는 레코드 유형에 대해 std_logic_vectors를 빠르게 패킹하고 압축을 푸는 헬퍼 절차 세트를 한 번 제시했습니다. 그의 proposed pack and unpack subprograms을 참조하십시오.

실무 그룹 자체에서 이러한 문제를 해결하는 방법에 대해 오랜 토론이있었습니다. 3 가지 가능성이 있습니다 :

  • VHDL은 엔티티 선언에 제네릭 형식을 지원합니다. 따라서 VHDL-2008 호환 합성 도구는 임의의 유형 *)을 FIFO 요소로 허용하는 일반 FIFO를 만들 수 있습니다.
  • VHDL-2017은 적어도 기록에서의 대화를 std_logic_vector으로 해결할 수있는 reflection API을 추가합니다. 나는 반대로 경로를 구현하는 아이디어에 노력하고있어.
  • 기록 소자를 반복 직접적인 솔루션은 아직 발견되지 않았고 다음 개정판 (VHDL-2020)

*) 상관 합성 스칼라 어레이 또는 기록 유형으로 지연된다.