Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Простой шаблон AXI4-lite master
Форум разработчиков электроники ELECTRONIX.ru > Программируемая логика ПЛИС (FPGA,CPLD, PLD) > Работаем с ПЛИС, области применения, выбор
count_enable
Сейчас перекраиваю пример код от Xilinx под себя, и идёт мне... ну в общем медленно дело движется. Нужен простой мастер, который по получении внешнего прерывания читает данные из внешней памяти. Т.е. алгоритм такой.
0-Резет
1-Код, исполняемый на процессоре записывает в мастер адрес, откуда мастер будет брать данные и адрес, куда мастер будет писать флаг конца чтения.
2-Мастер заполняет флаг паттерном типа АВАВАВАВ
3-Мастер ждёт прерывания на внешнем порту.
4-После прерывания мастер читает слово из адреса в DDR3 и записывает флаг другим паттерном - 0С0С0С0С
5-GOTO 3.

Буду весьма признателен за простой код мастера на AXI4, потому что в примере от Хилинха и слейв, и locallink, и фифо, и куча внутренних флагов, и всё в одном файле.
Maverick
Цитата(count_enable @ Jan 21 2014, 15:02) *
Сейчас перекраиваю пример код от Xilinx под себя, и идёт мне... ну в общем медленно дело движется. Нужен простой мастер, который по получении внешнего прерывания читает данные из внешней памяти. Т.е. алгоритм такой.
0-Резет
1-Код, исполняемый на процессоре записывает в мастер адрес, откуда мастер будет брать данные и адрес, куда мастер будет писать флаг конца чтения.
2-Мастер заполняет флаг паттерном типа АВАВАВАВ
3-Мастер ждёт прерывания на внешнем порту.
4-После прерывания мастер читает слово из адреса в DDR3 и записывает флаг другим паттерном - 0С0С0С0С
5-GOTO 3.

Буду весьма признателен за простой код мастера на AXI4, потому что в примере от Хилинха и слейв, и locallink, и фифо, и куча внутренних флагов, и всё в одном файле.

поиск не пробовали делать по форуму? (Сообщение #7)
Ваш алгоритм не делает, но пример мастера там человек дает...
count_enable
Большое спасибо за ссылку! Не догадался посмотреть в разделе SoPC. К сожалению, там Верилог (забыл уточнить - ищу VHDL), но даёт понятие о порядке работы с шиной.
Всё же, если у кого завалялся AXI Lite мастер на VHDL - буду весьма признателен.
Maverick
Цитата(count_enable @ Jan 22 2014, 00:18) *
Большое спасибо за ссылку! Не догадался посмотреть в разделе SoPC. К сожалению, там Верилог (забыл уточнить - ищу VHDL), но даёт понятие о порядке работы с шиной.
Всё же, если у кого завалялся AXI Lite мастер на VHDL - буду весьма признателен.

именно VHDL ...
count_enable
Ааа, Вы про m_axi_user_bridge.vhd ? Я не сразу понял, что он делает и смотрел на код _4afc_ из архива.
Для будущих поколений, есть Xilinx AR http://www.xilinx.com/support/answers/37425.htm на тему, с очень хорошими примерами - но на Верилоге.

Когда пробую подключить m_axi_user_bridge.vhd - требует сигналов ARADDR, ARSIZE и других, не описанных в дизайне. Подключаю через Create or Import Peripheral Wizard. Можно ли его как-то обойти? Полный DMA_controller тащить не хочу.
count_enable
Разобрался.
Создал код с нуля и спецификации шины.
Очень помог комментарий RobFPGA из этой шины http://electronix.ru/forum/index.php?showtopic=116819 .

Но пока не могу разобраться с таймаутами шины. Если моя корка неправильно написана, даже слейв, она вешает шину намертво и всю систему тоже. Кто может вкратце разъяснить как ведёт себя AXI_interconnect если слейв не отвечает или завис в момент транзакции?
Maverick
Цитата(count_enable @ Jan 24 2014, 18:37) *
Разобрался.
Создал код с нуля и спецификации шины.
Очень помог комментарий RobFPGA из этой шины http://electronix.ru/forum/index.php?showtopic=116819 .

Но пока не могу разобраться с таймаутами шины. Если моя корка неправильно написана, даже слейв, она вешает шину намертво и всю систему тоже. Кто может вкратце разъяснить как ведёт себя AXI_interconnect если слейв не отвечает или завис в момент транзакции?

я точно не скажу, но вроде слейв должен начинать транзакцию передачи пакета когда будут собраны данные для всего пакета (пакет = "длине" фифо). И не начинать транзакцию передачи пока фифо не будет полным (имеются все данные для пакета).
Причины зависания в момент транзакции?
Слейв используете свой или корка от Xilinx?

upd

только что перешел по ссылке, там в принципе тоже самое пишет RobFPGA
count_enable
Конечно поделюсь, только закончу еще слейв-часть. Пока что виснет, паскуда и не могу понять почему. В Isim все работает, но не использую Xilinxoвую модель, а дергаю шину вручную.

Слейв Акси-лайт, т.е одно слово. Два регистра. В симуляторе норм, вживую не поднимается в 1 S_AXI_AWREADY. Таймаут по шине не приходит, система тупо висит.

Код
---------------------------------------------------------
WRITE_PROC: process(M_AXI_ACLK) is
begin
if M_AXI_ARESETN='0' then
        conf_reg<=(others=>'0');
        addr_reg<=(others=>'0');
else
    if M_AXI_ACLK'event and M_AXI_ACLK='1' then
        case W_state is
            when ST_IDLE=>
                    if    S_AXI_AWVALID='1' then
                        S_AXI_AWREADY<='1';
                        W_state<=ST_WRITE;
                    end if;
            when ST_WRITE=>
                    S_AXI_AWREADY<='0';
                    S_AXI_WREADY<='1';
                    if S_AXI_WVALID='1' then
                        if S_AXI_AWADDR(0)='0' then
                            conf_reg<=S_AXI_WDATA;
                        else
                            addr_reg<=S_AXI_WDATA;
                        end if;
                        W_state<=ST_CONFIRM;
                    end if;
                when ST_CONFIRM=>
                    S_AXI_BRESP<="00";
                    S_AXI_WREADY<='0';
                    S_AXI_BVALID<='1';
                    if S_AXI_BREADY='1' then
                        S_AXI_BVALID<='0';
                        W_state<=ST_IDLE;
                    end if;            
        end case;
    end if;
end if;
end process;





ДОБАВЛЕНО:
Ёрш твою медь, есть ли где-то вменяемая времянка записи в Axi-lite? У меня проц почему-то первым делом BREADY поднимает.
Maverick
Цитата(count_enable @ Jan 24 2014, 20:44) *
ДОБАВЛЕНО:
Ёрш твою медь, есть ли где-то вменяемая времянка записи в Axi-lite? У меня проц почему-то первым делом BREADY поднимает.

вот это не подойдет?
count_enable
Хош сделать хорошо- сделай сам:
Вот времянки записи и чтения процессора из Xilinxoвой корки, т.е. самые правильные.
Запись:

Чтение:


На выходных постараюсь сложить всю инфу в кучу.
Я в курсе, что есть AXI4-IPIF, но чтобы разобраться надо работать на самом нижнем уровне. IPIF может оказаться излишним.
count_enable
Как и обещал, выкладываю свои шаблоны.
Мастер пишет по фиксированному адресу 4 фиксированных слова, потом их читает и отправляет во внешний порт. Проверка на ошибки шины не производится, поэтому виснет при неправильном адресе!

CODE
-------------------------------------------------------------------------------
--
-- AXI4-Lite Master
-- Simplified IP-core that performs 32-byte write to fixed address and reads it back
-- Does not perform error check on write and read!!!
--
-- VHDL-Standard: VHDL'93
----------------------------------------------------------------------------
--
-- Structure:
-- axi_lite_master
--
----------------------------------------------------------------------------

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_misc.all;
--library unisim;
--use unisim.vcomponents.all;

entity AXI4_master_lite is
generic(
C_M_AXI_ADDR_WIDTH : integer := 32;
C_M_AXI_DATA_WIDTH : integer := 32
);
port(

STATUS: out std_logic_vector(31 downto 0); -- output for debug purposes

-- System Signals
M_AXI_ACLK : in std_logic;
M_AXI_ARESETN : in std_logic;

-- Master Interface Write Address
M_AXI_AWADDR : out std_logic_vector(C_M_AXI_ADDR_WIDTH-1 downto 0);
M_AXI_AWPROT : out std_logic_vector(3-1 downto 0);
M_AXI_AWVALID : out std_logic;
M_AXI_AWREADY : in std_logic;

-- Master Interface Write Data
M_AXI_WDATA : out std_logic_vector(C_M_AXI_DATA_WIDTH-1 downto 0);
M_AXI_WSTRB : out std_logic_vector(C_M_AXI_DATA_WIDTH/8-1 downto 0);
M_AXI_WVALID : out std_logic;
M_AXI_WREADY : in std_logic;

-- Master Interface Write Response
M_AXI_BRESP : in std_logic_vector(2-1 downto 0);
M_AXI_BVALID : in std_logic;
M_AXI_BREADY : out std_logic;

-- Master Interface Read Address

M_AXI_ARADDR : out std_logic_vector(C_M_AXI_ADDR_WIDTH-1 downto 0);
M_AXI_ARPROT : out std_logic_vector(3-1 downto 0);
M_AXI_ARVALID : out std_logic;
M_AXI_ARREADY : in std_logic;

-- Master Interface Read Data
M_AXI_RDATA : in std_logic_vector(C_M_AXI_DATA_WIDTH-1 downto 0);
M_AXI_RRESP : in std_logic_vector(2-1 downto 0);
M_AXI_RVALID : in std_logic;
M_AXI_RREADY : out std_logic

);

end AXI4_master_lite;

-------------------------------------------------------------------------------
-- Architecture
-------------------------------------------------------------------------------
architecture implementation of AXI4_master_lite is
signal testreg: std_logic_vector (C_M_AXI_DATA_WIDTH-1 downto 0);
signal counter, ctrread: integer range 0 to 32;

type state_type is (ST_IDLE, ST_WRITE,ST_DWRITE,ST_DACK, ST_ACK,ST_BREADY);
signal state, next_state : state_type;
type Rstate_type is (ST_IDLE, ST_RADDR,ST_RDATA);
signal Rstate:Rstate_type;
signal start_read:std_logic;
begin
M_AXI_AWPROT<=(others=>'0');
M_AXI_ARPROT<=(others=>'0');

WRITE_SM: process (M_AXI_ACLK) is
begin
if M_AXI_ARESETN='0' then
testreg<=x"A5A5A5A5";
M_AXI_AWVALID<='0';
M_AXI_WVALID<='0';
M_AXI_BREADY<='0';
counter<=0;
state<=ST_IDLE;
start_read<='0';
STATUS(15 downto 0)<=(others=>'0');
else
if M_AXI_ACLK'event and M_AXI_ACLK='1' then
case state is
when ST_IDLE =>
M_AXI_AWVALID<='0';
M_AXI_WVALID<='0';
M_AXI_BREADY<='0';
if counter<31 then
state<=ST_WRITE;
STATUS(15 downto 0)<=x"0001";
else
state<=state;
start_read<='1'; -- after writes we initiate reading

end if;
when ST_WRITE =>
M_AXI_AWADDR(31 downto 8)<=x"A800F0";
M_AXI_AWADDR(7 downto 0)<=std_logic_vector(to_unsigned(counter,8));
M_AXI_WDATA<=testreg;
M_AXI_WSTRB<="1111";
M_AXI_AWVALID<='1';

M_AXI_WDATA<=testreg;
M_AXI_WSTRB<="1111";
M_AXI_WVALID<='1';
state<=ST_ACK;
STATUS(15 downto 0)<=x"0002";
when ST_ACK =>
if M_AXI_AWREADY='1' then
M_AXI_AWVALID<='0';
counter<=counter+4;
state<=ST_DACK;
STATUS(15 downto 0)<=x"0003";
else
next_state<=state;
end if;
when ST_DWRITE =>
M_AXI_WDATA<=testreg;
M_AXI_WSTRB<="1111";
M_AXI_WVALID<='1';
state<=ST_DACK;
STATUS(15 downto 0)<=x"0004";

when ST_DACK =>
if M_AXI_WREADY='1' then
M_AXI_WVALID<='0';
M_AXI_BREADY<='1';
state<=ST_BREADY;
STATUS(15 downto 0)<=x"0005";
else
state<=state;
end if;
when ST_BREADY =>
if M_AXI_BVALID='1' then
M_AXI_BREADY<='0';
state<=ST_IDLE;
STATUS(15 downto 0)<=x"0006";
else
state<=state;
end if;
end case;
end if;
end if;
end process;

READ_SM: process(M_AXI_ACLK) is
begin
if M_AXI_ARESETN='0' then
M_AXI_ARVALID<='0';
M_AXI_RREADY<='0';
Rstate<=ST_IDLE;
ctrread<=0;
STATUS(31 downto 16)<=(others=>'0');
else
if M_AXI_ACLK'event and M_AXI_ACLK='1' then
case Rstate is
when ST_IDLE =>
if start_read='1' and ctrread<31 then
Rstate<=ST_RADDR;
M_AXI_ARVALID<='1';
M_AXI_ARADDR(31 downto 8)<=x"A800F0";
M_AXI_ARADDR(7 downto 0)<=std_logic_vector(to_unsigned(ctrread,8));
end if;
when ST_RADDR =>
M_AXI_ARVALID<='0';
M_AXI_RREADY<='1';
if M_AXI_RVALID='1' then
ctrread<=ctrread+4;
STATUS(31 downto 16)<=M_AXI_RDATA(15 downto 0);
Rstate<=ST_RDATA;
end if;
when ST_RDATA =>
M_AXI_RREADY<='0';
Rstate<=ST_IDLE;
end case;
end if;
end if;
end process;
end implementation;


Слейв это 2 регистра, ошибок не возвращает (всегда можно прочитать). Проверка на валидность адреса тоже рудиментарная.
CODE
-------------------------------------------------------------------------------
--
-- AXI4-Lite Slave
--
-- VHDL-Standard: VHDL'93
----------------------------------------------------------------------------
--
-- Structure:
-- axi_lite_slave
--
----------------------------------------------------------------------------

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_misc.all;

--library unisim;
--use unisim.vcomponents.all;

entity axi_paer_router is
generic(
C_M_AXI_ADDR_WIDTH : integer := 32;
C_M_AXI_DATA_WIDTH : integer := 32;
C_S_AXI_ADDR_WIDTH : integer := 32;
C_S_AXI_DATA_WIDTH : integer := 32;
C_S_AXI_MIN_SIZE : std_logic_vector := X"000001FF";
C_USE_WSTRB : integer := 0;
C_DPHASE_TIMEOUT : integer := 8;
C_BASEADDR : std_logic_vector := X"00000000";
C_HIGHADDR : std_logic_vector := X"00000010";
C_FAMILY : string := "spartan6";
C_NUM_REG : integer := 1;
C_NUM_MEM : integer := 1;
C_SLV_AWIDTH : integer := 32;
C_SLV_DWIDTH : integer := 32
);
port(
-- System Signals
M_AXI_ACLK : in std_logic; -- это еще остались от мастер-слейва, поэтому не переименовал
M_AXI_ARESETN : in std_logic; -- это еще остались от мастер-слейва, поэтому не переименовал

-- Slave Interface Write Address Ports
S_AXI_AWADDR : in std_logic_vector(C_S_AXI_ADDR_WIDTH-1 downto 0);
S_AXI_AWPROT : in std_logic_vector(3-1 downto 0);
S_AXI_AWVALID : in std_logic;
S_AXI_AWREADY : out std_logic;

-- Slave Interface Write Data Ports
S_AXI_WDATA : in std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);
S_AXI_WSTRB : in std_logic_vector(C_S_AXI_DATA_WIDTH/8-1 downto 0);
S_AXI_WVALID : in std_logic;
S_AXI_WREADY : out std_logic;

-- Slave Interface Write Response Ports
S_AXI_BRESP : out std_logic_vector(2-1 downto 0);
S_AXI_BVALID : out std_logic;
S_AXI_BREADY : in std_logic;

-- Slave Interface Read Address Ports
S_AXI_ARADDR : in std_logic_vector(C_S_AXI_ADDR_WIDTH-1 downto 0);
S_AXI_ARPROT : in std_logic_vector(3-1 downto 0);
S_AXI_ARVALID : in std_logic;
S_AXI_ARREADY : out std_logic;

-- Slave Interface Read Data Ports
S_AXI_RDATA : out std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);
S_AXI_RRESP : out std_logic_vector(2-1 downto 0);
S_AXI_RVALID : out std_logic;
S_AXI_RREADY : in std_logic

);

end axi_paer_router;

-------------------------------------------------------------------------------
-- Architecture
-------------------------------------------------------------------------------
architecture implementation of axi_paer_router is
signal conf_reg: std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0); -- вот и память слейва, 2 регистра
signal addr_reg: std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);
type Rstate_type is (ST_IDLE, ST_READ);
signal R_state : Rstate_type;
type Wstate_type is (ST_IDLE,ST_WRITE, ST_CONFIRM);
signal W_state : Wstate_type;
begin
---------------------------------------------------------
WRITE_PROC: process(M_AXI_ACLK) is
begin
if M_AXI_ARESETN='0' then
conf_reg<=(others=>'0');
addr_reg<=(others=>'0');
else
if M_AXI_ACLK'event and M_AXI_ACLK='1' then
case W_state is
when ST_IDLE=>
S_AXI_BVALID<='0';
if S_AXI_AWVALID='1' then
S_AXI_AWREADY<='1';
W_state<=ST_WRITE;
end if;
when ST_WRITE=>
S_AXI_AWREADY<='0';
if S_AXI_WVALID='1' then
S_AXI_WREADY<='1';
if S_AXI_AWADDR(2)='0' then -- every 4th byte (either XXXXXXX0 or XXXXXXX4)
conf_reg<=S_AXI_WDATA;
else
addr_reg<=S_AXI_WDATA; -- вот такая примитивная адресация - все адреса мапированы в 2 рег
end if;
W_state<=ST_CONFIRM;
end if;
when ST_CONFIRM=>
S_AXI_BRESP<="00";
S_AXI_WREADY<='0';
S_AXI_BVALID<='1';
if S_AXI_BREADY='1' then
W_state<=ST_IDLE;
end if;
end case;
end if;
end if;
end process;
---------------------------------------------------------
READ_PROC: process (M_AXI_ACLK) is
begin
if M_AXI_ARESETN='0' then
R_state<=ST_IDLE;
else
if M_AXI_ACLK'event and M_AXI_ACLK='1' then
S_AXI_ARREADY<='0';
S_AXI_RVALID<='0';
S_AXI_RRESP<="00";
case R_state is
when ST_IDLE=>
if S_AXI_ARVALID='1' then
S_AXI_ARREADY<='1';
R_state<=ST_READ;
else R_state<=R_state;
end if;
when ST_READ =>
S_AXI_ARREADY<='0';
S_AXI_RVALID<='1';
S_AXI_RRESP<="00";
if S_AXI_ARADDR(2)='0' then -- every 4th byte (either XXXXXXX0 or XXXXXXX4)
S_AXI_RDATA<=conf_reg;
else
S_AXI_RDATA<=addr_reg;
end if;
if S_AXI_RREADY ='1' then
R_state<=ST_IDLE;
else R_state<=R_state;
end if;
end case;
end if;
end if;
end process;
end implementation;


Если кто-то не хочет использовать Xilinx IPIF, может воспользоваться вышеприведенными шаблонами для собственных корок. Лицензия WTFPL sm.gif. Обе корки протестированы в железе, собирались на xc6slx45 с микроблейзом в ИСЕ 14.2.
Помогла документация:
http://www.xilinx.com/support/documentatio..._ipif_ds765.pdf
http://www.xilinx.com/support/documentatio...master_lite.pdf
http://home.mit.bme.hu/~feher/MSC_RA/ARM/A...otocol_spec.pdf
По возможности постараюсь помочь, если у кого-то будут вопросы. На самом деле шина значительно проще чем кажется - глаза боятся, а руки делают.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.