|
|
  |
Как записать данные в память из AXImaster?, ADC->AXI4->MCB3 |
|
|
|
Nov 14 2013, 10:12
|
Участник

Группа: Участник
Сообщений: 21
Регистрация: 17-02-09
Пользователь №: 44 975

|
Цитата(_4afc_ @ Nov 14 2013, 12:37)  Вопрос 1: Что производительнее/проще - 1 добавить второй порт к памяти и через отдельную шину AXI4 записывать данные своим мастером? 2 добавить второго мастера на существующую шину? AXI4 подразумевает соединение точка-точка - это не шина. Инфраструктура строится с использованием axi switch'ей. Если добавить в mig'е второй порт, будет быстрее и проще. Реализация axi интерфейсов есть, например, в xapp1168. Vivado 2013.3 умеет генерировать шаблоны, такие же как в xapp1168.
|
|
|
|
|
Nov 14 2013, 11:56
|
Профессионал
    
Группа: Свой
Сообщений: 1 214
Регистрация: 23-12-04
Пользователь №: 1 643

|
Приветствую! Цитата(m_m @ Nov 14 2013, 12:12)  AXI4 подразумевает соединение точка-точка - это не шина. Инфраструктура строится с использованием axi switch'ей.
Если добавить в mig'е второй порт, будет быстрее и проще. ... Все в кучу смешали - и MIGи и шины и кони  Раз уже есть система с Microblaze и LPDDR то значить есть и axi_interconet - это и есть тот самый "switch" MIG с в системах с AXI шиной имеет только один порт который как раз цепляется к axi_interconet. В случае _4afc_ есть несколько вариантов - "soft" - цепляете в EDK axi_dma к axi_interconet - данные ADC гоните по axi_stream через DMA; требуется соответственно поддержка в софте (драйвер axi_dma уже готовые есть). "hard" - делаете свой аналог axi_dma... ну а затем действия те же что и в варианте soft  (но еще и драйвер самому ваят) "crazy" - делаете свой контроллер DDR с несколькими портами axi... ну а затем все как и в предыдущих вариантах 8-() В принципе автомат пересылки данных по axi4 не сложен - тем более если не заморачивается с поддержкой всех режимов работы шины. Так что вариант "hard" вполне реализуем. Так же EDK есть возможность создавать свою периферию с axi* шинами - при этом можно создать модуль адаптера axi_master который имеет боле простую шину со стороны user для обмена данными - громоздко но если по быстрому склепать что то на коленке - сойдет. Успехов! Rob.
|
|
|
|
|
Nov 14 2013, 12:54
|

Профессионал
    
Группа: Свой
Сообщений: 1 262
Регистрация: 13-10-05
Из: Санкт-Петербург
Пользователь №: 9 565

|
Цитата(RobFPGA @ Nov 14 2013, 14:56)  Раз уже есть система с Microblaze и LPDDR то значить есть и axi_interconet - это и есть тот самый "switch" MIG с в системах с AXI шиной имеет только один порт который как раз цепляется к axi_interconet. Но я могу включить в MCB3 второй порт и соединиться с ним из своего ip по второму axi_interconet. Есть ли в таком разделении смысл? Цитата(RobFPGA @ Nov 14 2013, 14:56)  "soft" - цепляете в EDK axi_dma к axi_interconet - данные ADC гоните по axi_stream через DMA; требуется соответственно поддержка в софте (драйвер axi_dma уже готовые есть). Где взять axi_dma в EDK? Или вы про AXImaster_burst или stream? Я пока не увидел лёгкости в том что генерит EDK. Цитата(RobFPGA @ Nov 14 2013, 14:56)  "hard" - делаете свой аналог axi_dma... ну а затем действия те же что и в варианте soft  (но еще и драйвер самому ваят) Написать своё иногда легче, чем понять чужое. Вопрос - где-то описан порядок работы AXImaster в режиме dma? Цитата(RobFPGA @ Nov 14 2013, 14:56)  "crazy" - делаете свой контроллер DDR с несколькими портами axi... ну а затем все как и в предыдущих вариантах 8-() Так визард EDK вроде позволяет контроллеру DDR иметь несколько axi, или потом это не синтезируется? Цитата(RobFPGA @ Nov 14 2013, 14:56)  В принципе автомат пересылки данных по axi4 не сложен - тем более если не заморачивается с поддержкой всех режимов работы шины. Так что вариант "hard" вполне реализуем. А немогли бы вы на пальцах описать порядок действий мастера в этом режиме? Цитата(RobFPGA @ Nov 14 2013, 14:56)  Так же EDK есть возможность создавать свою периферию с axi* шинами - при этом можно создать модуль адаптера axi_master который имеет боле простую шину со стороны user для обмена данными - громоздко но если по быстрому склепать что то на коленке - сойдет. Вот именно громоздкость полученного при этом результата - меня пугает. Кроме того в варианте "crazy" я могу FIFO иметь не в AXImaster, а в MCB3. В мастере иногда нужно поставить пару буферов. Цитата(m_m @ Nov 14 2013, 13:12)  AXI4 подразумевает соединение точка-точка - это не шина. Инфраструктура строится с использованием axi switch'ей. Если добавить в mig'е второй порт, будет быстрее и проще. Реализация axi интерфейсов есть, например, в xapp1168. Vivado 2013.3 умеет генерировать шаблоны, такие же как в xapp1168. Спасибо, изучаю xapp1168. Вы предлагаете сгенерить шаблон в Vivado 2013.3 и сделать по аналогии в EDK или Vivado научился со Spartan работать?
|
|
|
|
|
Nov 14 2013, 13:09
|
Участник

Группа: Участник
Сообщений: 21
Регистрация: 17-02-09
Пользователь №: 44 975

|
Цитата(_4afc_ @ Nov 14 2013, 16:54)  Спасибо, изучаю xapp1168. Вы предлагаете сгенерить шаблон в Vivado 2013.3 и сделать по аналогии в EDK или Vivado научился со Spartan работать? Я предлагаю взять шаблон из Vivado или xapp1168, сделать на основе его свой axi master, в mig'е добавить еще порт и подключить этот мастер к нему. Под шаблоном я понимаю verilog или vhdl файл.
|
|
|
|
|
Nov 14 2013, 14:25
|
Профессионал
    
Группа: Свой
Сообщений: 1 214
Регистрация: 23-12-04
Пользователь №: 1 643

|
Приветствую! Цитата(_4afc_ @ Nov 14 2013, 14:54)  Но я могу включить в MCB3 второй порт и соединиться с ним из своего ip по второму axi_interconet. Есть ли в таком разделении смысл?
Так визард EDK вроде позволяет контроллеру DDR иметь несколько axi, или потом это не синтезируется? Упс голова чугунная - запамятовал что в Spartan hard контроллер DDR и уже имеет несколько портов - sorry. Да - в этом случае конечно смысл есть - проще получится структура interconect. Цитата(_4afc_ @ Nov 14 2013, 14:54)  Где взять axi_dma в EDK? Или вы про AXImaster_burst или stream? Я пока не увидел лёгкости в том что генерит EDK. В EDK 14.3 и выше есть AXI DMA engine - это полный DMA (вариант "soft") AXI datamover - это как видно из названия кусок DMA который непосредственно перегоняет данные (им нужно самому рулить но можно фантазировать от души) Цитата(_4afc_ @ Nov 14 2013, 14:54)  Написать своё иногда легче, чем понять чужое. Вопрос - где-то описан порядок работы AXImaster в режиме dma? А немогли бы вы на пальцах описать порядок действий мастера в этом режиме? В соответствии с протоколом axi любая транзакция по либой части шины проходит тогда когда *valid=1 *ready=1 Пишите данные ADC в FIFO, Поскольку у Вас ADC 8 бит то лучше на этом этапе упаковать их в 32-64 бита в соответствии с разрядностью шины. Копите в этом FIFO число слов данных равное требуемому burst. По шине aw* пишете запрос на запись: awaddr адрес куда пишете очередной блок данных awlen длинна burst остальные поля - hardcod параметров в соответствии размерности шины соответственно ставите awvalid=1, ждете awready=1 По шине данных wdata пересылаете нужное количество слов в соответствии длинной burst (соответственно ставите wvalid=1, ждете wready=1) все - данные полетели на запись в темные недра DDR Ждете подтверждения на шине bresp (соответственно ставите bready=1, ждете bvalid=1) получив подтверждение - уменьшили счетчик слов - увеличили адрес буфера если получили OK - то можете отправлять следующий запрос на запись ну а если BAD - то "ШЕФ усе пропало! " для системы Microblaze скорее всего Вы выставили неправильный адрес - abort, exeptions ну и портянка лога на десяток экранов  если счетчик==0 - все переслано "тютелько в тютельку" - надо бить в колокола - дергать прерывания - задавать новый адрес и размер буфера и начинать все по новой. В принципе запрос на запись и пересылка данных могут идти в любом порядке да еще и не дожидаясь подтверждения окончания предыдущих. Главное чтобы всех "тварей" было по три  Это увеличивает скорость передачи но и усложняет реализацию. В Вашем случае скорость маленькая так что можно не заморачивается. Ух аж вспотел - заодно и освежил в памяти что и как. Успехов! Rob.
|
|
|
|
|
Nov 14 2013, 16:01
|
Участник

Группа: Участник
Сообщений: 19
Регистрация: 23-06-05
Пользователь №: 6 251

|
Для AXI Master не забудьте про "multiple outstanding transactions". Вот код для примера, тоже для себя делали: axi_controller_dma.vhd CODE library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all;
library unisim; use unisim.vcomponents.all;
entity AXI_CONTROLLER_DMA is generic (C_S_AXI_BASEADDR : std_logic_vector(31 downto 0) := X"FFFF0000"; C_S_AXI_HIGHADDR : std_logic_vector(31 downto 0) := X"FFFFFFFF"); port ( -- AXI Slave Interface AXI_ACLK : in std_logic; AXI_RESETN : in std_logic;
-- AXI Slave Write Address Channel S_AXI_AWADDR : in std_logic_vector(31 downto 0); S_AXI_AWPROT : in std_logic_vector(2 downto 0); S_AXI_AWVALID : in std_logic; S_AXI_AWREADY : out std_logic;
-- AXI Slave Write Data Channel S_AXI_WDATA : in std_logic_vector(31 downto 0); S_AXI_WSTRB : in std_logic_vector(3 downto 0); S_AXI_WVALID : in std_logic; S_AXI_WREADY : out std_logic;
--AXI4 Write Response Channel S_AXI_BRESP : out std_logic_vector(1 downto 0); S_AXI_BVALID : out std_logic; S_AXI_BREADY : in std_logic;
-- AXI Slave Read Address Channel S_AXI_ARADDR : in std_logic_vector(31 downto 0); S_AXI_ARPROT : in std_logic_vector(2 downto 0); S_AXI_ARVALID : in std_logic; S_AXI_ARREADY : out std_logic;
-- AXI Slave Read Data Channel S_AXI_RDATA : out std_logic_vector(31 downto 0); S_AXI_RRESP : out std_logic_vector(1 downto 0); S_AXI_RVALID : out std_logic; S_AXI_RREADY : in std_logic;
-- AXI4 Master Write Channel -- Write Address Channel M_AXI_AWREADY : in std_logic; M_AXI_AWVALID : out std_logic; M_AXI_AWADDR : out std_logic_vector(31 downto 0); M_AXI_AWLEN : out std_logic_vector(7 downto 0); M_AXI_AWSIZE : out std_logic_vector(2 downto 0); M_AXI_AWBURST : out std_logic_vector(1 downto 0); M_AXI_AWPROT : out std_logic_vector(2 downto 0); M_AXI_AWCACHE : out std_logic_vector(3 downto 0);
-- Write Data Channel M_AXI_WREADY : in std_logic ; M_AXI_WVALID : out std_logic; M_AXI_WDATA : out std_logic_vector(63 downto 0); M_AXI_WSTRB : out std_logic_vector(7 downto 0); M_AXI_WLAST : out std_logic;
-- Write Response Channel M_AXI_BREADY : out std_logic; M_AXI_BVALID : in std_logic; M_AXI_BRESP : in std_logic_vector(1 downto 0) );
end AXI_CONTROLLER_DMA;
architecture RTL of AXI_CONTROLLER_DMA is
component m_axi_users_bridge port ( -- axi slave interface axi_aclk : in std_logic; axi_resetn : in std_logic;
------------------------------ -- axi4 master write channel ------------------------------ -- write address channel m_axi_awready : in std_logic; m_axi_awvalid : out std_logic; m_axi_awaddr : out std_logic_vector(31 downto 0); m_axi_awlen : out std_logic_vector(7 downto 0); m_axi_awsize : out std_logic_vector(2 downto 0); m_axi_awburst : out std_logic_vector(1 downto 0); m_axi_awprot : out std_logic_vector(2 downto 0); m_axi_awcache : out std_logic_vector(3 downto 0);
-- write data channel m_axi_wready : in std_logic ; m_axi_wvalid : out std_logic; m_axi_wdata : out std_logic_vector(63 downto 0); m_axi_wstrb : out std_logic_vector(7 downto 0); m_axi_wlast : out std_logic;
-- write response channel m_axi_bready : out std_logic; m_axi_bvalid : in std_logic; m_axi_bresp : in std_logic_vector(1 downto 0);
------------------------------ -- write user channel ------------------------------ user_wr_req : in std_logic; user_wr_addr : in std_logic_vector(31 downto 0); user_wr_lenght : in std_logic_vector(15 downto 0); user_wr_ack : out std_logic; user_wr_tvalid : in std_logic; user_wr_tdata : in std_logic_vector(63 downto 0); user_wr_tlast : in std_logic; user_wr_tready : out std_logic); end component; component s_axi_user_bridge port( axi_aclk : in std_logic; axi_resetn : in std_logic;
-- AXI Slave Write Address Channel s_axi_awaddr : in std_logic_vector(31 downto 0); s_axi_awvalid : in std_logic; s_axi_awready : out std_logic; s_axi_awprot : in std_logic_vector(2 downto 0); -- AXI Slave Write Data Channel s_axi_wdata : in std_logic_vector(31 downto 0); s_axi_wstrb : in std_logic_vector(3 downto 0); s_axi_wvalid : in std_logic; s_axi_wready : out std_logic; -- AXI4 Write Response Channel s_axi_bresp : out std_logic_vector(1 downto 0); s_axi_bvalid : out std_logic; s_axi_bready : in std_logic;
-- AXI Slave Read Address Channel s_axi_araddr : in std_logic_vector(31 downto 0); s_axi_arvalid : in std_logic; s_axi_arready : out std_logic; s_axi_arprot : in std_logic_vector(2 downto 0); -- AXI Slave Read Data Channel s_axi_rdata : out std_logic_vector(31 downto 0); s_axi_rresp : out std_logic_vector(1 downto 0); s_axi_rvalid : out std_logic; s_axi_rready : in std_logic ; -- User Read/Write Data Channel user_reset : out std_logic; user_addr : out std_logic_vector(31 downto 0); user_wdata : out std_logic_vector(31 downto 0); user_rdata : in std_logic_vector(31 downto 0); user_be : out std_logic_vector(3 downto 0); user_wreq : out std_logic; user_wack : in std_logic; user_rreq : out std_logic; user_rack : in std_logic); end component;
function n_dec_bit(baddr,haddr : std_logic_vector(31 downto 0)) return integer is variable baddr_xor_haddr : std_logic_vector(31 downto 0); begin baddr_xor_haddr := baddr xor haddr; for i in 31 downto 0 loop if baddr_xor_haddr(i) = '1' then return(i+1); end if; end loop; return(32); end function n_dec_bit;
constant c_s_axi_n_dec_bit : integer := n_dec_bit(C_S_AXI_BASEADDR,C_S_AXI_HIGHADDR)-1;
constant ADR_REG_BASEADDR : std_logic_vector(31 downto 0) := X"00000000"; constant LENGHT_REG_BASEADDR : std_logic_vector(31 downto 0) := X"00000004"; constant CNT_REG_BASEADDR : std_logic_vector(31 downto 0) := X"00000008"; --constant TIME_REG_BASEADDR : std_logic_vector(31 downto 0) := X"0000000c";
constant adr_reg_n_dec_bit : integer := n_dec_bit(ADR_REG_BASEADDR, X"00000003"); constant lenght_reg_n_dec_bit : integer := n_dec_bit(LENGHT_REG_BASEADDR, X"00000007"); constant cnt_reg_n_dec_bit : integer := n_dec_bit(CNT_REG_BASEADDR, X"0000000B"); --constant time_reg_n_dec_bit : integer := n_dec_bit(time_reg_BASEADDR, X"0000000f");
-- User Read/Write signals signal user_reset : std_logic; signal user_addr : std_logic_vector(31 downto 0); signal user_wdata : std_logic_vector(31 downto 0); signal user_rdata : std_logic_vector(31 downto 0); signal user_be : std_logic_vector(3 downto 0); signal user_wreq : std_logic; signal user_wack : std_logic; signal user_rreq : std_logic; signal user_rack : std_logic;
signal read_addr : std_logic_vector(2 downto 0);
signal adr_reg : std_logic_vector(31 downto 0); signal lenght_reg : std_logic_vector(31 downto 0); signal cnt_reg : std_logic_vector(31 downto 0) := (others=>'0');
signal adr_reg_ce : std_logic; signal lenght_reg_ce : std_logic; signal cnt_reg_ce : std_logic; --signal time_reg_ce : std_logic;
signal dac_count : std_logic_vector(13 downto 0);
signal m_user_wr_req : std_logic; signal m_user_wr_addr : std_logic_vector(31 downto 0) := (others=>'0'); signal m_user_wr_lenght : std_logic_vector(16 downto 0) := (others=>'0'); signal m_user_wr_ack : std_logic; signal m_user_wr_tvalid : std_logic := '0'; signal m_user_wr_tdata : std_logic_vector(63 downto 0) := (others=>'0'); signal m_user_wr_tdata_i : std_logic_vector(31 downto 0) := (others=>'0'); signal m_user_wr_tdata_j : std_logic_vector(31 downto 0) := (others=>'0'); signal m_user_wr_tlast : std_logic := '0'; signal m_user_wr_tready : std_logic := '0';
signal time_reg : std_logic_vector(31 downto 0) := (others=>'0'); signal count_time_reg_en , count_lenght_en : std_logic := '0';
type state_type is (ST_IDLE, ST_DATA); signal state ,next_state : state_type;
begin
----------------------------------------------------------- -----------------------------------------------------------
s_axi_user_bridge_inst : s_axi_user_bridge port map( axi_aclk => AXI_ACLK, axi_resetn => AXI_RESETN,
s_axi_awaddr => s_axi_awaddr, s_axi_awvalid => s_axi_awvalid, s_axi_awready => s_axi_awready, s_axi_awprot => s_axi_awprot, s_axi_wdata => s_axi_wdata, s_axi_wstrb => s_axi_wstrb, s_axi_wvalid => s_axi_wvalid, s_axi_wready => s_axi_wready, s_axi_bresp => s_axi_bresp, s_axi_bvalid => s_axi_bvalid, s_axi_bready => s_axi_bready,
s_axi_araddr => s_axi_araddr, s_axi_arvalid => s_axi_arvalid, s_axi_arready => s_axi_arready, s_axi_arprot => s_axi_arprot, s_axi_rdata => s_axi_rdata, s_axi_rresp => s_axi_rresp, s_axi_rvalid => s_axi_rvalid, s_axi_rready => s_axi_rready, user_reset => user_reset, user_addr => user_addr, user_wdata => user_wdata, user_rdata => user_rdata, user_be => user_be, user_wreq => user_wreq, user_wack => user_wack, user_rreq => user_rreq, user_rack => user_rack); -----------------------------------------------------------
adr_reg_ce <= '1' when (user_addr(c_s_axi_n_dec_bit downto adr_reg_n_dec_bit) = ADR_REG_BASEADDR(c_s_axi_n_dec_bit downto adr_reg_n_dec_bit)) else '0'; lenght_reg_ce <= '1' when (user_addr(c_s_axi_n_dec_bit downto lenght_reg_n_dec_bit) = LENGHT_REG_BASEADDR(c_s_axi_n_dec_bit downto lenght_reg_n_dec_bit)) else '0'; cnt_reg_ce <= '1' when (user_addr(c_s_axi_n_dec_bit downto cnt_reg_n_dec_bit) = CNT_REG_BASEADDR(c_s_axi_n_dec_bit downto cnt_reg_n_dec_bit)) else '0'; --time_reg_ce <= '1' when (user_addr(c_s_axi_n_dec_bit downto time_reg_n_dec_bit) = TIME_REG_BASEADDR(c_s_axi_n_dec_bit downto time_reg_n_dec_bit)) else '0';
-- User Write Data Channel
user_wack <= '1' when (user_wreq = '1' and (lenght_reg_ce = '1' or adr_reg_ce = '1' or cnt_reg_ce = '1')) else '0';
user_rack <= user_rreq;
process ( AXI_ACLK , user_reset ) begin if ( AXI_ACLK = '1' and AXI_ACLK 'event) then if (user_reset ='1') then adr_reg <= (others => '0'); lenght_reg <= (others => '0'); elsif (user_wreq = '1') then if ( adr_reg_ce = '1') then adr_reg <= user_wdata; end if; if ( lenght_reg_ce = '1') then lenght_reg <= user_wdata; end if; -- if ( cnt_reg_ce = '1') then -- cnt_reg <= user_wdata; -- end if; end if; end if; end process; -----------------------------------------------------------
-- AXI Slave_User Read Data Channel read_addr <= user_addr(4 downto 2);
process (read_addr, cnt_reg, adr_reg, lenght_reg, cnt_reg, time_reg) begin case (read_addr) is when "000" => user_rdata <= adr_reg; when "001" => user_rdata <= lenght_reg; when "010" => user_rdata <= cnt_reg; when "011" => user_rdata <= time_reg; when others => user_rdata <= x"ffffffff"; end case; end process; ----------------------------------------------------------- -----------------------------------------------------------
m_axi_users_bridge_inst: m_axi_users_bridge port map( axi_aclk => axi_aclk, axi_resetn => axi_resetn,
m_axi_awready => m_axi_awready, m_axi_awvalid => m_axi_awvalid, m_axi_awaddr => m_axi_awaddr, m_axi_awlen => m_axi_awlen, m_axi_awsize => m_axi_awsize, m_axi_awburst => m_axi_awburst, m_axi_awprot => m_axi_awprot, m_axi_awcache => m_axi_awcache,
m_axi_wready => m_axi_wready, m_axi_wvalid => m_axi_wvalid, m_axi_wdata => m_axi_wdata, m_axi_wstrb => m_axi_wstrb, m_axi_wlast => m_axi_wlast,
m_axi_bready => m_axi_bready, m_axi_bvalid => m_axi_bvalid, m_axi_bresp => m_axi_bresp,
user_wr_req => m_user_wr_req, user_wr_addr => m_user_wr_addr, user_wr_lenght => lenght_reg(15 downto 0), user_wr_ack => m_user_wr_ack, user_wr_tvalid => m_user_wr_tvalid, user_wr_tdata => m_user_wr_tdata, user_wr_tlast => m_user_wr_tlast, user_wr_tready => m_user_wr_tready); -----------------------------------------------------------
m_user_wr_addr <= adr_reg; -----------------------------------------------------------
process (AXI_ACLK, user_reset) begin if (AXI_ACLK'event and AXI_ACLK = '1') then if (user_reset = '1') then state <= ST_IDLE; else state <= next_state; end if; end if; end process;
process (state, cnt_reg_ce, user_wreq, user_wdata, m_user_wr_ack, m_user_wr_lenght,m_user_wr_tready) begin
m_user_wr_req <= '0'; m_user_wr_tvalid <= '0'; m_user_wr_tlast <= '0'; count_time_reg_en <= '0'; cnt_reg(0) <= '0'; next_state <= state; case state is when ST_IDLE => if (cnt_reg_ce = '1' and user_wreq = '1' and user_wdata(0) = '1') then m_user_wr_req <= '1'; cnt_reg(0) <= '1'; end if; if( m_user_wr_ack = '1') then cnt_reg(0) <= '1'; next_state <= ST_DATA; end if; when ST_DATA => cnt_reg(0) <= '1'; m_user_wr_tvalid <= '1'; m_user_wr_tlast <= m_user_wr_lenght(16); if(m_user_wr_lenght(16) = '1' and m_user_wr_tready = '1') then next_state <= ST_IDLE; end if;
end case; end process; -----------------------------------------------------------
process (AXI_ACLK) begin if (AXI_ACLK'event and AXI_ACLK = '1') then if (m_user_wr_ack = '1') then time_reg <= (others=>'0'); elsif (cnt_reg(0) = '1') then-- time_reg <= time_reg + 1; end if; end if; end process; -----------------------------------------------------------
process (AXI_ACLK) begin if (AXI_ACLK'event and AXI_ACLK = '1') then if (m_user_wr_ack = '1') then m_user_wr_tdata_i <= (others=>'0'); m_user_wr_tdata_j <= x"00000001";-- elsif (m_user_wr_tready = '1') then m_user_wr_tdata_i <= m_user_wr_tdata_i + 2; m_user_wr_tdata_j <= m_user_wr_tdata_j + 2; end if; end if; end process; m_user_wr_tdata <= x"00000000" & m_user_wr_tdata_i;--m_user_wr_tdata_j -----------------------------------------------------------
process (AXI_ACLK) begin if (AXI_ACLK'event and AXI_ACLK = '1') then if (m_user_wr_ack = '1') then m_user_wr_lenght <= ('0'&lenght_reg(15 downto 0)) - 1; elsif (m_user_wr_tready = '1') then m_user_wr_lenght <= m_user_wr_lenght - 1; end if; end if; end process; ----------------------------------------------------------- ----------------------------------------------------------- end RTL;
m_axi_user_bridge.vhd CODE library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_unsigned.all;
library unisim; use unisim.vcomponents.all;
entity M_AXI_USERS_BRIDGE is
port ( -- AXI Interface AXI_ACLK : in std_logic; AXI_RESETN : in std_logic;
----------------------------------------------------------------------------- ----------------------------------------------------------------------------- -- AXI4 Master Write Channel ----------------------------------------------------------------------------- -- Write Address Channel M_AXI_AWREADY : in std_logic; M_AXI_AWVALID : out std_logic; M_AXI_AWADDR : out std_logic_vector(31 downto 0); M_AXI_AWLEN : out std_logic_vector(7 downto 0); M_AXI_AWSIZE : out std_logic_vector(2 downto 0); M_AXI_AWBURST : out std_logic_vector(1 downto 0); M_AXI_AWPROT : out std_logic_vector(2 downto 0); M_AXI_AWCACHE : out std_logic_vector(3 downto 0);
-- Write Data Channel M_AXI_WREADY : in std_logic ; M_AXI_WVALID : out std_logic; M_AXI_WDATA : out std_logic_vector(63 downto 0); M_AXI_WSTRB : out std_logic_vector(7 downto 0); M_AXI_WLAST : out std_logic;
-- Write Response Channel M_AXI_BREADY : out std_logic; M_AXI_BVALID : in std_logic; M_AXI_BRESP : in std_logic_vector(1 downto 0);
----------------------------------------------------------------------------- -- Write User Channel ----------------------------------------------------------------------------- USER_WR_REQ : in std_logic; USER_WR_ADDR : in std_logic_vector(31 downto 0); USER_WR_LENGHT : in std_logic_vector(15 downto 0); USER_WR_ACK : out std_logic; USER_WR_TVALID : in std_logic; USER_WR_TDATA : in std_logic_vector(63 downto 0); USER_WR_TLAST : in std_logic; USER_WR_TREADY : out std_logic );
end M_AXI_USERS_BRIDGE;
architecture RTL of M_AXI_USERS_BRIDGE is
type state_type is (ST_IDLE, ST_ADDR); signal state, next_state : state_type;
signal count_awlen : std_logic_vector(16 downto 0):= (others => '0'); signal count_awaddr : std_logic_vector(31 downto 0):= (others => '0');
signal count_addr_load : std_logic; signal count_addr_en : std_logic;
signal count_data : std_logic_vector(4 downto 0):= (others => '0'); signal count_data_init : std_logic; signal count_data_en : std_logic;
signal count_addr_que : std_logic_vector(4 downto 0):= (others => '0');
-----------------------------------------------------------------------
begin
M_AXI_AWSIZE <= "011"; M_AXI_AWBURST <= "01"; M_AXI_AWPROT <= (others => '0'); M_AXI_AWCACHE <= (others => '0'); M_AXI_WSTRB <= x"ff"; M_AXI_BREADY <= '1';
M_AXI_AWADDR <= count_awaddr; M_AXI_AWLEN <= x"0f" when( count_awlen(16) = '0') else "0000" & count_awlen(3 downto 0);
M_AXI_WVALID <= USER_WR_TVALID; M_AXI_WDATA <= USER_WR_TDATA;
USER_WR_TREADY <= M_AXI_WREADY;
----------------------------------------------------------- ----------------------------------------------------------- process (AXI_ACLK, AXI_RESETN) begin if (AXI_ACLK'event and AXI_ACLK = '1') then if (AXI_RESETN = '0') then state <= ST_IDLE; else state <= next_state; end if; end if; end process;
process (state, USER_WR_REQ, count_awlen, M_AXI_AWREADY) begin
M_AXI_AWVALID <= '0'; USER_WR_ACK <= '0'; count_addr_load <= '0'; count_addr_en <= '0'; next_state <= state;
case state is
when ST_IDLE => if (USER_WR_REQ = '1') then USER_WR_ACK <= '1'; count_addr_load <= '1'; next_state <= ST_ADDR; end if; when ST_ADDR => M_AXI_AWVALID <= '1'; count_addr_en <= M_AXI_AWREADY; if (count_awlen(16) = '1' and M_AXI_AWREADY = '1') then next_state <= ST_IDLE; end if;
end case; end process; -----------------------------------------------------------
process (AXI_ACLK) begin if (AXI_ACLK'event and AXI_ACLK = '1') then if (count_addr_load = '1') then count_awaddr(31 downto 3) <= USER_WR_ADDR(31 downto 3); count_awlen <= ('0'&USER_WR_LENGHT) - 16; elsif (count_addr_en = '1') then count_awaddr(31 downto 3) <= count_awaddr(31 downto 3) + 16; count_awlen <= count_awlen - 16; end if; end if; end process; -----------------------------------------------------------
count_data_en <= '1' when (( USER_WR_TVALID = '1' and M_AXI_WREADY = '1') or AXI_RESETN = '0') else '0'; count_data_init <= '1' when ((count_data(4) = '1' or USER_WR_TLAST = '1') or AXI_RESETN = '0') else '0'; M_AXI_WLAST <= count_data_init; -----------------------------------------------------------
process (AXI_ACLK) begin if (AXI_ACLK'event and AXI_ACLK = '1') then if (count_data_en = '1') then if (count_data_init = '1') then count_data <= "00000" + 1; else count_data <= count_data + 1; end if; end if; end if; end process; -----------------------------------------------------------
end RTL;
|
|
|
|
|
Nov 19 2013, 07:31
|
Профессионал
    
Группа: Свой
Сообщений: 1 214
Регистрация: 23-12-04
Пользователь №: 1 643

|
Приветствую! Цитата(dmitry-tomsk @ Nov 19 2013, 08:53)  Вариант axi stream master + data mover менее эффективен будет, чем axi full master? Немного не понял вопрос. Что Вы имели в виду под axi full master? И что является критерием эффективности? data_mover это и есть full master контроллер на AXI шине. Использование data_mover позволяет сделать свое "хитрое" (ну и понятно что более эффективное конкретно для Вас  ) управление пересылками. То есть например формировать дескрипторы не только софтом из CPU но и аппаратно - например с помощью FSM. Или опять же например пересылать данные от нескольких источников по разным цепочкам дескрипторов. Естественно чем хитрее будут Ваши фантазии в управлении тем сложнее (и ясен пень менее эффективно  ) их можно будет реализовывать. Успехов. Rob.
|
|
|
|
|
Nov 19 2013, 08:10
|

Профессионал
    
Группа: Свой
Сообщений: 1 262
Регистрация: 13-10-05
Из: Санкт-Петербург
Пользователь №: 9 565

|
Цитата(ilyge @ Nov 14 2013, 19:01)  Для AXI Master не забудьте про "multiple outstanding transactions". Что-то не нашёл где и как я должен это учитывать и на что это повлияет. Цитата(m_m @ Nov 14 2013, 16:09)  Я предлагаю взять шаблон из Vivado или xapp1168, сделать на основе его свой axi master, в mig'е добавить еще порт и подключить этот мастер к нему. Под шаблоном я понимаю verilog или vhdl файл. Удалось прикрутить мастера из xapp1168 к EDK14.4. В результате он заполняет числами 640 байт памяти с адреса 0xA1000000 выполняя 10 burst по 16 слов. Затем их даже вроде читает обратно и проверяет. Единственное, что в этом мастере не подключены порты m_axi_arprot и m_axi_awprot шины AXI4, не знаю насколько это плохо. Сейчас в проекте у памяти один порт, который делится между Microblaze и моим мастером (me3). Рад что благодаря форуму удалось избавится от громоздкого ipif в своих ядрах!!! Пойду прикручивать АЦП к этому мастеру, заодно посравниваю реализацию m_m с алгоритмами RobFPGA и ilyge
Эскизы прикрепленных изображений
|
|
|
|
|
Nov 19 2013, 08:24
|
Знающий
   
Группа: Свой
Сообщений: 672
Регистрация: 18-02-05
Пользователь №: 2 741

|
Цитата(RobFPGA @ Nov 19 2013, 10:31)  Приветствую! Немного не понял вопрос. Что Вы имели в виду под axi full master? И что является критерием эффективности? data_mover это и есть full master контроллер на AXI шине. Использование data_mover позволяет сделать свое "хитрое" (ну и понятно что более эффективное конкретно для Вас  ) управление пересылками. То есть например формировать дескрипторы не только софтом из CPU но и аппаратно - например с помощью FSM. Или опять же например пересылать данные от нескольких источников по разным цепочкам дескрипторов. Естественно чем хитрее будут Ваши фантазии в управлении тем сложнее (и ясен пень менее эффективно  ) их можно будет реализовывать. Успехов. Rob. Есть же axi_lite и axi_full варианты. По поводу АЦП. Не всегда же стоит задача только в память данные бросить, у нас, как правило, в параллель ЦОС обработка работает. Axi stream гораздо более удобен в этом плане. Вот я и спрашиваю по ресурсам и частоте какой вариант лучше? Кроме того, ведь надо делать где-то переход с частоты АЦП на частоту порта MCB, пускай удвоенную к АЦП для простоты, и здесь размера FIFO, встроенного в MCB не хватает (проверено на не Axi проектах). Где лучше делать переход на другую частоту?
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|