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

Создание IP для AXI4 light

Здравствуйте. Подскажите пожалуйста, как можно правильно подключить VHDL ядро RAM к шине AXI4.

Задача: необходимо аппаратное ядро буфер RAM подключить к AXi4 для считывания данных из буфера с помощью microblaze.

 

пока пробую простой вариант для rom.

Что делаю: в ISE создаю проект, добавляю mblz. Открываю XPS и там создаю новое ядро. Есть два файла: user_logic.vhdl и топовый файл ядра.

В user_logic.vhd добавляю rom. En на считывание завожу на статусный регистр считывания данных из IP ядра (slv_reg_read_sel = "0100").

 

Далее в SDK пытаюсь считать из регистра содержимое rom.

 

user_logic код

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

library proc_common_v3_00_a;
use proc_common_v3_00_a.proc_common_pkg.all;

-- DO NOT EDIT ABOVE THIS LINE --------------------

--USER libraries added here

------------------------------------------------------------------------------
-- Entity section
------------------------------------------------------------------------------
-- Definition of Generics:
--   C_NUM_REG                    -- Number of software accessible registers
--   C_SLV_DWIDTH                 -- Slave interface data bus width
--
-- Definition of Ports:
--   Bus2IP_Clk                   -- Bus to IP clock
--   Bus2IP_Resetn                -- Bus to IP reset
--   Bus2IP_Data                  -- Bus to IP data bus
--   Bus2IP_BE                    -- Bus to IP byte enables
--   Bus2IP_RdCE                  -- Bus to IP read chip enable
--   Bus2IP_WrCE                  -- Bus to IP write chip enable
--   IP2Bus_Data                  -- IP to Bus data bus
--   IP2Bus_RdAck                 -- IP to Bus read transfer acknowledgement
--   IP2Bus_WrAck                 -- IP to Bus write transfer acknowledgement
--   IP2Bus_Error                 -- IP to Bus error response
------------------------------------------------------------------------------

entity user_logic is
  generic
  (
    -- ADD USER GENERICS BELOW THIS LINE ---------------
    --USER generics added here
    -- ADD USER GENERICS ABOVE THIS LINE ---------------

    -- DO NOT EDIT BELOW THIS LINE ---------------------
    -- Bus protocol parameters, do not add to or delete
    C_NUM_REG                      : integer              := 4;
    C_SLV_DWIDTH                   : integer              := 32
    -- DO NOT EDIT ABOVE THIS LINE ---------------------
  );
  port
  (
    -- ADD USER PORTS BELOW THIS LINE ------------------
    --USER ports added here
    LEDS_OUT      : out std_logic_vector(7 downto 0);    
    DATA_OUT      : out std_logic_vector(7 downto 0);     
     RDEN          : out std_logic;
     EOF_P         : out std_logic;
    -- ADD USER PORTS ABOVE THIS LINE ------------------

    -- DO NOT EDIT BELOW THIS LINE ---------------------
    -- Bus protocol ports, do not add to or delete
    Bus2IP_Clk                     : in  std_logic;
    Bus2IP_Resetn                  : in  std_logic;
    Bus2IP_Data                    : in  std_logic_vector(C_SLV_DWIDTH-1 downto 0);
    Bus2IP_BE                      : in  std_logic_vector(C_SLV_DWIDTH/8-1 downto 0);
    Bus2IP_RdCE                    : in  std_logic_vector(C_NUM_REG-1 downto 0);
    Bus2IP_WrCE                    : in  std_logic_vector(C_NUM_REG-1 downto 0);
    IP2Bus_Data                    : out std_logic_vector(C_SLV_DWIDTH-1 downto 0);
    IP2Bus_RdAck                   : out std_logic;
    IP2Bus_WrAck                   : out std_logic;
    IP2Bus_Error                   : out std_logic
    -- DO NOT EDIT ABOVE THIS LINE ---------------------
  );

  attribute MAX_FANOUT : string;
  attribute SIGIS : string;

  attribute SIGIS of Bus2IP_Clk    : signal is "CLK";
  attribute SIGIS of Bus2IP_Resetn : signal is "RST";

end entity user_logic;

------------------------------------------------------------------------------
-- Architecture section
------------------------------------------------------------------------------

architecture IMP of user_logic is

  --USER signal declarations added here, as needed for user logic
  
   type rom_type is array (15 downto 0) of std_logic_vector (7 downto 0);                 
   signal ROM_arr : rom_type:= (X"01", X"10", X"02", X"20", X"03", X"30",
                             X"04", X"40", X"05", X"50", X"06", X"60",
                             X"07", X"70", X"08", X"80");                        

    signal rdata : std_logic_vector(7 downto 0);
    signal  ADDR : std_logic_vector(3 downto 0);
  
  
                  
  signal SWITCH_IN  : std_logic_vector(7 downto 0);
  signal RD_EN, EOF : std_logic;
  ------------------------------------------
  -- Signals for user logic slave model s/w accessible register example
  ------------------------------------------
  signal slv_reg0                       : std_logic_vector(C_SLV_DWIDTH-1 downto 0);
  signal slv_reg1                       : std_logic_vector(C_SLV_DWIDTH-1 downto 0);
  signal slv_reg2                       : std_logic_vector(C_SLV_DWIDTH-1 downto 0);
  signal slv_reg3                       : std_logic_vector(C_SLV_DWIDTH-1 downto 0);
  signal slv_reg_write_sel              : std_logic_vector(3 downto 0);
  signal slv_reg_read_sel               : std_logic_vector(3 downto 0);
  signal slv_ip2bus_data                : std_logic_vector(C_SLV_DWIDTH-1 downto 0);
  signal slv_read_ack                   : std_logic;
  signal slv_write_ack                  : std_logic;

begin

-- сигналы для контроля в chipscope

DATA_OUT <=  SWITCH_IN;
RDEN  <= RD_EN;
EOF_P <= EOF;


rdata <= ROM_arr(conv_integer(ADDR));

    process (Bus2IP_Clk)
    begin
        if (Bus2IP_Clk'event and Bus2IP_Clk = '1') then
           if (RD_EN = '1') then
                SWITCH_IN <= rdata;
                     ADDR <= ADDR + 1;
                else
                    ADDR <= (others => '0');
            end if;
        end if;
    end process;
     
     EOF <= '1' when ADDR = x"E" else '0';


  ------------------------------------------
  -- Example code to read/write user logic slave model s/w accessible registers
  -- 
  -- Note:
  -- The example code presented here is to show you one way of reading/writing
  -- software accessible registers implemented in the user logic slave model.
  -- Each bit of the Bus2IP_WrCE/Bus2IP_RdCE signals is configured to correspond
  -- to one software accessible register by the top level template. For example,
  -- if you have four 32 bit software accessible registers in the user logic,
  -- you are basically operating on the following memory mapped registers:
  -- 
  --    Bus2IP_WrCE/Bus2IP_RdCE   Memory Mapped Register
  --                     "1000"   C_BASEADDR + 0x0
  --                     "0100"   C_BASEADDR + 0x4
  --                     "0010"   C_BASEADDR + 0x8
  --                     "0001"   C_BASEADDR + 0xC
  -- 
  ------------------------------------------
  slv_reg_write_sel <= Bus2IP_WrCE(3 downto 0);
  slv_reg_read_sel  <= Bus2IP_RdCE(3 downto 0);
  slv_write_ack     <= Bus2IP_WrCE(0) or Bus2IP_WrCE(1) or Bus2IP_WrCE(2) or Bus2IP_WrCE(3);
  slv_read_ack      <= Bus2IP_RdCE(0) or Bus2IP_RdCE(1) or Bus2IP_RdCE(2) or Bus2IP_RdCE(3);

  -- implement slave model software accessible register(s)
  SLAVE_REG_WRITE_PROC : process( Bus2IP_Clk ) is
  begin

    if Bus2IP_Clk'event and Bus2IP_Clk = '1' then
      if Bus2IP_Resetn = '0' then
        slv_reg0 <= (others => '0');
        slv_reg1 <= (others => '0');
        slv_reg2 <= (others => '0');
        slv_reg3 <= (others => '0');
      else
        case slv_reg_write_sel is
          when "1000" =>
            for byte_index in 0 to (C_SLV_DWIDTH/8)-1 loop
              if ( Bus2IP_BE(byte_index) = '1' ) then
                slv_reg0(byte_index*8+7 downto byte_index*8) <= Bus2IP_Data(byte_index*8+7 downto byte_index*8);
              end if;
            end loop;
          when "0100" =>
            for byte_index in 0 to (C_SLV_DWIDTH/8)-1 loop
              if ( Bus2IP_BE(byte_index) = '1' ) then
                slv_reg1(byte_index*8+7 downto byte_index*8) <= Bus2IP_Data(byte_index*8+7 downto byte_index*8);
              end if;
            end loop;
          when "0010" =>
            for byte_index in 0 to (C_SLV_DWIDTH/8)-1 loop
              if ( Bus2IP_BE(byte_index) = '1' ) then
                slv_reg2(byte_index*8+7 downto byte_index*8) <= Bus2IP_Data(byte_index*8+7 downto byte_index*8);
              end if;
            end loop;
          when "0001" =>
            for byte_index in 0 to (C_SLV_DWIDTH/8)-1 loop
              if ( Bus2IP_BE(byte_index) = '1' ) then
                slv_reg3(byte_index*8+7 downto byte_index*8) <= Bus2IP_Data(byte_index*8+7 downto byte_index*8);
              end if;
            end loop;
          when others => null;
        end case;
      end if;
    end if;

  end process SLAVE_REG_WRITE_PROC;

  -- implement slave model software accessible register(s) read mux
  SLAVE_REG_READ_PROC : process( slv_reg_read_sel, slv_reg0, slv_reg1, slv_reg2, slv_reg3 ) is
  begin

    case slv_reg_read_sel is
      when "1000" => slv_ip2bus_data <= slv_reg0;
      when "0100" => slv_ip2bus_data <= x"000000" & SWITCH_IN;
      when "0010" => slv_ip2bus_data <= x"0000000" & "000" & EOF;
      when "0001" => slv_ip2bus_data <= slv_reg3;
      when others => slv_ip2bus_data <= (others => '0');
    end case;

  end process SLAVE_REG_READ_PROC;

  ------------------------------------------
  -- Example code to drive IP to Bus signals
  ------------------------------------------
  IP2Bus_Data  <= slv_ip2bus_data when slv_read_ack = '1' else
                  (others => '0');

  IP2Bus_WrAck <= slv_write_ack;
  IP2Bus_RdAck <= slv_read_ack;
  IP2Bus_Error <= '0';

LEDS_OUT <= slv_reg0(7 downto 0);

RD_EN <= '1' when slv_reg_read_sel = "0100" else '0';
end IMP;

 

и собственно код в SDK

int main()
{  u8  sw[16];

while(1){

              for(i = 0; i <= 15; i++)
              {
                   sw[i] = Xil_In8(MY_CORE_REG_BASEADDR + 0x04);// +0x04 т.к. slv_reg_read_sel = "0100"
              }
                     
}
    return 0;
}

Если я правильно понимаю, то пока работает Xil_In8, то slv_reg_read_sel = "0100" и следовательно моя rom считывается. Но chipscopom вижу что это не так.

Какие есть еще варианты реализации?

 

В Altere я просто создавал ram HDL файл, одни ноги из которого шли на шину (типа read_en, addr, data), а другие снаружу в аппаратную часть (wr_en, addr, data). Создавал ядро. Далее в Eclipse ставил указатель на base addr ядра и вычитывал данные с адр пространства.

 

Посоветуйте пожалуйста как лучше сделать в Xilinx.

 

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


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

В ксалинксе надо в платформ студии нажать вкладку создания и импорт модулей. Нажать создать новый регистровый модуль, пометить галкой вместе с проектом ISE.

В ISE открыть созданный проект, и в user.vhdl у вас будет шаблон чтения и записи в регистры по адресам. ну дальше все переписать под себя сбилдить модуль, и импортировать его обратно в платформ студию, подключить к микроблайзу и обращаться к ядру через адреса.

 

судя по тексту выше вы примерно это и получили, тогда остается понять логику внутри, правильная ли она

кстати что такое Xil_In8 ?

 

все что висит на шине доступно просто через

 

int *data = (int *)(MY_CORE_REG_BASEADDR + 0x04);

 

*data = 5; //записать

int temp = *data; //считать

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


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

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

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

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

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

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

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

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

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

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