Jump to content

    
Sign in to follow this  
Aleksei_Rostov

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

Recommended Posts

Здравствуйте. Подскажите пожалуйста, как можно правильно подключить 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.

 

Share this post


Link to post
Share on other sites

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

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

 

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

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

 

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

 

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

 

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

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

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this