레코드 유형이 입/출력되는 FIFO를 가정하면 실제 FIFO에서 FIFO 래퍼 및 std_logic_vector의 입력 및 출력에서 레코드 유형 간의 매핑을 처리하는 간단한 방법이 있습니까?VHDL/FPGA의 FIFO에 레코드를 쓰거나 읽는 간단한 방법이 있습니까?
0
A
답변
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)
*) 상관 합성 스칼라 어레이 또는 기록 유형으로 지연된다.
필자는 이것을 올바르게 이해한다고 가정하고 FIFO에 대한 입/출력 레코드를 사용하기로 결정했습니다. 레코드를 입력으로 사용하고 std_logic_vector를 반환하는 함수를 사용하지 마십시오. 그 반대의 경우도 마찬가지입니다. –
가정은 정확합니다. 이 함수들이 단순화되었거나 예제 응답에 표시된 것보다 작성하기 쉬운 오류가 적은 예제가 있습니까? – FritzDC
나는 오류가 덜 발생하는 능력에 대해 확신하지 못하는 예제를 추가 할 것이다 - 당신이 더 잘 판단 할 수있을 것 같다. –