Перейти к содержанию
    

Как записать данные в память из AXImaster?

Есть АЦП 8бит 25МГц подключенный к Spartan6 у которого есть Microblaze и LPDDR.

Microblaze прекрасно читает и пишет в LPDDR как мастер на шине AXI.

Хочется добавить своего максимально простого мастера который будет заполнять память данными из АЦП.

 

Думаю начать с мастера который просто заполняет память нулями - дальше всё вроде понятно.

Опыт написания AXIslave есть.

 

Вопрос 1:

Что производительнее/проще -

1 добавить второй порт к памяти и через отдельную шину AXI4 записывать данные своим мастером?

2 добавить второго мастера на существующую шину?

 

Вопрос 2:

 

Какова поледовательность посылки данных мастером?

 

Если создать AXImaster_burst в визарде, то он предлагает перебросить данные из своего FIFO за 5 манипуляций с регистрами IP:

1. write 0x02 to the control register to perform write operation.

2. write the target address to the address register

3. write valid byte lane value to the be register

4. write 0x0040 to the length register

5. write 0x0a to the go register, this will start the master write operation

но как заполнить его FIFO из IP и манипулировать этими регистрами непонятно.

 

Если создать axi_ext_master_conn, то получаем пустую болванку и что в неё писать - загадка.

 

Может есть у кого примерчик простенького AXI мастера?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вопрос 1:

Что производительнее/проще -

1 добавить второй порт к памяти и через отдельную шину AXI4 записывать данные своим мастером?

2 добавить второго мастера на существующую шину?

 

AXI4 подразумевает соединение точка-точка - это не шина. Инфраструктура строится с использованием axi switch'ей.

 

Если добавить в mig'е второй порт, будет быстрее и проще.

 

Реализация axi интерфейсов есть, например, в xapp1168. Vivado 2013.3 умеет генерировать шаблоны, такие же как в xapp1168.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Приветствую!

 

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.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Раз уже есть система с Microblaze и LPDDR то значить есть и axi_interconet - это и есть тот самый "switch"

MIG с в системах с AXI шиной имеет только один порт который как раз цепляется к axi_interconet.

Но я могу включить в MCB3 второй порт и соединиться с ним из своего ip по второму axi_interconet.

Есть ли в таком разделении смысл?

 

"soft" - цепляете в EDK axi_dma к axi_interconet - данные ADC гоните по axi_stream через DMA;

требуется соответственно поддержка в софте (драйвер axi_dma уже готовые есть).

Где взять axi_dma в EDK? Или вы про AXImaster_burst или stream? Я пока не увидел лёгкости в том что генерит EDK.

 

"hard" - делаете свой аналог axi_dma... ну а затем действия те же что и в варианте soft :) (но еще и драйвер самому ваят)

Написать своё иногда легче, чем понять чужое. Вопрос - где-то описан порядок работы AXImaster в режиме dma?

 

"crazy" - делаете свой контроллер DDR с несколькими портами axi... ну а затем все как и в предыдущих вариантах 8-()

Так визард EDK вроде позволяет контроллеру DDR иметь несколько axi, или потом это не синтезируется?

 

В принципе автомат пересылки данных по axi4 не сложен - тем более если не заморачивается с поддержкой всех режимов работы шины. Так что вариант "hard" вполне реализуем.

А немогли бы вы на пальцах описать порядок действий мастера в этом режиме?

 

Так же EDK есть возможность создавать свою периферию с axi* шинами - при этом можно создать модуль адаптера axi_master который имеет боле простую шину со стороны user для обмена данными - громоздко но если по быстрому склепать что то на коленке - сойдет.

Вот именно громоздкость полученного при этом результата - меня пугает. Кроме того в варианте "crazy" я могу FIFO иметь не в AXImaster, а в MCB3. В мастере иногда нужно поставить пару буферов.

 

AXI4 подразумевает соединение точка-точка - это не шина. Инфраструктура строится с использованием axi switch'ей.

Если добавить в mig'е второй порт, будет быстрее и проще.

Реализация axi интерфейсов есть, например, в xapp1168. Vivado 2013.3 умеет генерировать шаблоны, такие же как в xapp1168.

 

Спасибо, изучаю xapp1168.

Вы предлагаете сгенерить шаблон в Vivado 2013.3 и сделать по аналогии в EDK или Vivado научился со Spartan работать?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Спасибо, изучаю xapp1168.

Вы предлагаете сгенерить шаблон в Vivado 2013.3 и сделать по аналогии в EDK или Vivado научился со Spartan работать?

 

Я предлагаю взять шаблон из Vivado или xapp1168, сделать на основе его свой axi master, в mig'е добавить еще порт и подключить

этот мастер к нему.

 

Под шаблоном я понимаю verilog или vhdl файл.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Приветствую!

 

 

Но я могу включить в MCB3 второй порт и соединиться с ним из своего ip по второму axi_interconet.

Есть ли в таком разделении смысл?

 

Так визард EDK вроде позволяет контроллеру DDR иметь несколько axi, или потом это не синтезируется?

 

Упс голова чугунная - запамятовал что в Spartan hard контроллер DDR и уже имеет несколько портов - sorry.

Да - в этом случае конечно смысл есть - проще получится структура interconect.

 

Где взять axi_dma в EDK? Или вы про AXImaster_burst или stream? Я пока не увидел лёгкости в том что генерит EDK.

 

В EDK 14.3 и выше есть

AXI DMA engine - это полный DMA (вариант "soft")

AXI datamover - это как видно из названия кусок DMA который непосредственно перегоняет данные (им нужно самому рулить но можно фантазировать от души)

 

Написать своё иногда легче, чем понять чужое. Вопрос - где-то описан порядок работы 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.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Для AXI Master не забудьте про "multiple outstanding transactions".

 

Вот код для примера, тоже для себя делали:

 

axi_controller_dma.vhd

 

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

 

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;

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Приветствую!

 

Вариант axi stream master + data mover менее эффективен будет, чем axi full master?

Немного не понял вопрос. Что Вы имели в виду под axi full master? И что является критерием эффективности?

data_mover это и есть full master контроллер на AXI шине.

Использование data_mover позволяет сделать свое "хитрое" (ну и понятно что более эффективное конкретно для Вас:) ) управление пересылками.

То есть например формировать дескрипторы не только софтом из CPU но и аппаратно - например с помощью FSM.

Или опять же например пересылать данные от нескольких источников по разным цепочкам дескрипторов.

 

Естественно чем хитрее будут Ваши фантазии в управлении тем сложнее (и ясен пень менее эффективно :( ) их можно будет реализовывать.

 

Успехов. Rob.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Для AXI Master не забудьте про "multiple outstanding transactions".

 

Что-то не нашёл где и как я должен это учитывать и на что это повлияет.

 

 

Я предлагаю взять шаблон из 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 :)

post-9565-1384848569_thumb.png

me3_v1_00_a.zip

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Приветствую!

 

 

Немного не понял вопрос. Что Вы имели в виду под axi full master? И что является критерием эффективности?

data_mover это и есть full master контроллер на AXI шине.

Использование data_mover позволяет сделать свое "хитрое" (ну и понятно что более эффективное конкретно для Вас:) ) управление пересылками.

То есть например формировать дескрипторы не только софтом из CPU но и аппаратно - например с помощью FSM.

Или опять же например пересылать данные от нескольких источников по разным цепочкам дескрипторов.

 

Естественно чем хитрее будут Ваши фантазии в управлении тем сложнее (и ясен пень менее эффективно :( ) их можно будет реализовывать.

 

Успехов. Rob.

Есть же axi_lite и axi_full варианты. По поводу АЦП. Не всегда же стоит задача только в память данные бросить, у нас, как правило, в параллель ЦОС обработка работает. Axi stream гораздо более удобен в этом плане. Вот я и спрашиваю по ресурсам и частоте какой вариант лучше?

 

Кроме того, ведь надо делать где-то переход с частоты АЦП на частоту порта MCB, пускай удвоенную к АЦП для простоты, и здесь размера FIFO, встроенного в MCB не хватает (проверено на не Axi проектах). Где лучше делать переход на другую частоту?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вопросы dmitry-tomsk из последнего сообщения всё ещё актуальны, так на них никто и не ответил...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...