Реализация Avalon-MM Master в виде конечного автомата на VHDL
Автор: Бортников Анатолий Юрьевич, генеральный директор компании ООО «РСВ ЭЛЕКТРОНИКС», кандидат физ.- мат. наук.
Введение.
Шина Avalon-MM является одной из стандартных шин передачи данных, используемых в ПЛИС фирмы Intel. Использование этой шины в своих модулях для передачи данных существенно повышает их возможность повторного применения и повышает надежность проектов. Также упрощается интеграция модулей в проект с помощью Platform Designer.
Принципы работы шины Avalon-MM.
Шина Avalon-MM используется для передачи данных между модулями проекта. Она позволяет выполнять запись данных в модуль либо чтение данных из модуля обращаясь к нему как к блоку памяти.
На шине Avalon-MM существует определенная иерархия модулей. Обязательно должен быть контроллер — Master, который управляет всеми транзакциями передачи данных по шине. Остальные модули выступают в роли подчиненных — Slave. Каждый Slave на шине имеет определенный адрес или диапазон адресов, в которые Master может писать данные или читать из этих адресов. На рис. 1 представлен вариант конфигурации шины Avalon-MM.
Рис 1. Вариант конфигурации шины Avalon-MM
В качестве мастера часто выступает процессор NIOS II либо может использоваться другой модуль в качестве процессора. Если использовать NIOS II то проблем с подключением к шине Avalon-MM не возникает. Так как он уже имеет встроенный интерфейс Avalon-MM Master. Если же есть необходимость использовать процессор без интерфейса Avalon-MM (например когда процессор пишется пользователем под конкретную задачу) то для его подключения к шине Avalon-MM требуется реализация интерфейса Avalon-MM Master.
Так как для управления периферией предполагается выполнение операций записи и чтения данных, рассмотрим минимально необходимый для этого набор сигналов интерфейса Avalon-MM Master, представленный в таблице 1.
Таблица 1. Сигналы шины Avalon-MM, минимальный набор
Название | разряды | направление | описание |
---|---|---|---|
address | 1–32 | выход | address представляет адрес байта независимо от ширины шины данных. Значение адреса должно быть выровнено по ширине шины данных. Для записи отдельных байтов с шины данных требуется использовать сигналы byteenable. Мастер всегда выставляет адрес независимо от ширины шины данных. Система межсоединений конвертирует этот адрес в адрес слов в адресном пространстве Slave-модуля. |
read, read_n | 1 | выход | Сигнал запроса операции чтения. Не требуется, если Master никогда не инициализирует операцию чтения. Но если есть сигналы read/read_n то readdata обязательны. |
readdata | 8, 16, 32, 64, 128, 256, 512, 1024 | вход | Сигналы для чтения данных. |
write write_n | 1 | выход | Сигнал запроса операции записи. Не требуется, если Master никогда не инициализирует операцию записи данных. Но если есть write/write_n то сигналы writedata обязательны. |
writedata | 8, 16, 32, 64, 128, 256, 512, 1024 | вход | Сигналы для передачи данных для записи в Slave. Если присутствуют writedata и readdata, то они должны быть одинаковой разрядности. |
byteenable byteenable_n | 1, 2, 4, 8, 16, 32, 64, 128 | выход | Сигналы активизируют отдельные байты данных при передаче, если разрядность шины данных больше 8. Каждый бит в byteenable соответствует отдельному байту в шине данных как при чтении так и при записи. Единица в бите byteenable показывает, будет ли передан этот байт по шине данных. Остальные байты в шине данных должны игнорироваться Slave-ом. Если требуется передать больше чем 1 байт по шине данных, то все байты должны быть выставлены. Количество передаваемых байт должно быть равно степени 2. Доступны следующие варианты значения сигналов byteenable и количество передаваемых байт: 1111 — передача 4-х байтов (32 бита); 0011 — передача младших двух байт (16 бит); 1100 — передача старших двух байт (16 бит); 0001 — передача младшего (первого) байта; 0010 — передача второго байта; 0100 — передача третье байта; 1000 — передача четвертого байта; |
waitrequest waitrequest_n | 1 | вход | Сигнал ожидания завершения транзакции. waitrequest выставляется Svale-ом, в случае, если он не может в данный момент принять входные данные или выдать данные для чтения. Master ожидает пока waitrequest не сбросится, чтобы завершить транзакцию. В это время Master не должен переключать сигналы на шине Avalon-MM. |
Как было упомянуто выше, все передачи данных инициализирует Master. Передачи данных осуществляется словами. Разрядность слов настраивается дискретными значениями в диапазоне от 8 бит до 1024 бит. Активные байты в передаваемых словах обозначаются маской в сигналах byteenable или byteenable_n.
Slave может приостановить передачу данных выставив в единицу сигнал waitrequest. Тогда, пока сигнал waitrequest равен 1, Master находится в режиме ожидания и не имеет права переключать сигналы интерфейса. Транзакция может завершиться только когда Slave сбросит сигнал waitrequest в 0 на рис. 2 представлены временные диаграммы записи и чтения данных.
Рис. 2 Временные диаграммы записи и чтения данных по шине Avalon-MM.
Master начинает чтение данных выставляя сигналы address, byteenable и read. Slave выдает данные на readdata в течение следующего такта clk.
Master считывает данные с readdata и сбрасывает сигнал read, заканчивая тем самым операцию чтения данных. И тут же начинает операцию записи данных выставляя сигналы address, byteenable, write и данные на writedata.
Сигнал waitrequest не выставляется в единицу по следующему фронту clk, следовательно по этому фронту заканчивается операция записи. Master сбрасывает сигнал write.
Master выставляет address, byteenable, writedata и write начиная следующую операцию записи. Тут же Slave поднимает сигнал waitrequest, сообщая, что он не готов в данный момент обрабатывать данные. Поэтому Master удерживает без изменения все сигналы шины Avalon-MM.
waitrequest сброшен, и тут операция записи завершается. И сразу Master начинает следующую операцию чтения выставляя сигналы read, address, byteenable. Slave, в свою очередь, поднимает сигнал waitrequest, сообщая, что он занят выполнением другой операции и не может в данный момент выставить данные на выход readdata. На следующем такте Slave выставляет данные на шину readdata и сбрасывает сигнал waitrequest.
waitreqiuest сброшен на следующем фронте сигнала clk, следовательно на этом фронте clk операция чтения завершается.
Реализация интерфейса Avalon-MM Master в виде конечного автомата
Если посмотреть внимательно на временные диаграммы записи чтения данных изображенных на рис. 2, то можно увидеть, что интерфейс при каждой транзакции проходит одни и те же состояния. Следовательно его можно реализовать в виде конечного автомата. Но сначала определим порты для нашего интерфейса Avalon-MM Master.
Порты интерфейса Avalon-MM Master
Представим наш интерфейс Avalon-MM Master как отдельный модуль, встраиваемый в какой-либо процессор или контроллер в следующем виде рис. 3.
Рис. 3 Графическое обозначение модуля Avalon-MM Master.
Описание портов ввода-вывода на языке VHDL для компонента Avalon-MM Master, графическое представление которого изображено на рис. 3, приведено ниже в листинге 1.
Листинг 1: Описание портов ввода\вывода для Avalon-MM Master
PORT(
nReset : IN STD_LOGIC;
Clock : IN STD_LOGIC;
------------ Processor Interface --------------------
CPU_WrEn : IN STD_LOGIC;
CPU_RdEn : IN STD_LOGIC;
CPU_AddrIn : IN STD_LOGIC_VECTOR( 7 DOWNTO 0 );
CPU_WrDataIn : IN STD_LOGIC_VECTOR( 31 DOWNTO 0 );
CPU_ByteEnCode : IN STD_LOGIC_VECTOR( 3 DOWNTO 0 );
CPU_Ready : OUT STD_LOGIC;
CPU_RdDataOut : OUT STD_LOGIC_VECTOR( 31 DOWNTO 0 );
---------- Avalon-MM Master interface --------------
avm_readdata : IN STD_LOGIC_VECTOR( 31 DOWNTO 0 );
avm_readdatavalid : IN STD_LOGIC;
avm_address : OUT STD_LOGIC_VECTOR( 7 DOWNTO 0 );
avm_byteenable : OUT STD_LOGIC_VECTOR( 3 DOWNTO 0 );
avm_read : OUT STD_LOGIC;
avm_write : OUT STD_LOGIC;
avm_writedata : OUT STD_LOGIC_VECTOR( 31 DOWNTO 0 )
);
Согласно таблице 1, разрядность и шин данных avm_writedata и avm_readdata равны между собой. Разрядность сигналов avm_byteenable равна разрядность шин данных деленной на 8. Каждый бит в avm_byteenable ставится в соответствии байту на шине данных.
Разрядность шина адреса avm_address составляет в данном случае 8 бит. Разрядность шины адреса выбирается в зависимости от того, насколько большие области адресов памяти выделяются для компонентов периферии.
Если в проекте не используются модули встроенной памяти или контроллеры доступа к внешней памяти SDRAM, DDR-DDR3, то скорее всего большая разрядность шины адреса не потребуется.
Однако, если предполагается работа с перечисленными выше контроллера доступа к памяти, то может потребоваться достаточно большая разрядность шины адреса: 8, 16, 24, 32 бита.
Это связано с тем, что для модулей периферии выделяются относительно не большие объемы памяти — буквально несколько регистров. Ниже перечислены самые распространенные регистры, которые присутствуют практически в каждом периферийном модуле:
регистр записи данных;
регистр чтения данных
регистр управления и настройки
регистр статуса
Для модулей работы с памятью, в свою очередь, выделяются гораздо большие массивы памяти, что требует большей разрядности шины адреса.
Описание конечного автомата
На рис. 4 представлена диаграмма состояний конечного автомата интерфейса Avalon-MM Master.
Рис. 4 Диаграмма состояний конечного автомата интерфейса Avalon-MM Master
После подачи питания конечный автомат попадает в состояние сброса FSM_RESET. Где сбрасываются в исходные состояния все внутренние переменные и сигналы шины Avalon-MM.
На следующем такте конечный автомат переходит в состояние ожидания FSM_IDLE. Это исходное состояние автомата для работы с шиной Avalon-MM. В этом состоянии автомат ожидает команду от процессора. В листинге 2 представлен исходный код, описывающий это состояние на VHDL.
Листинг 2. Исходный код реализации состояния FSM_IDLE
WHEN FSM_IDLE =>
IF( CPU_WrEn = '1' ) THEN
MasterAddr <= CPU_AddrIn;
MasterData <= CPU_WrDataIn;
FSM_MasterState <= FSM_WRITE;
ELSIF( CPU_RdEn = '1' ) THEN
MasterAddr <= CPU_AddrIn;
FSM_MasterState <= FSM_READ;
ELSE
MasterAddr <= ( OTHERS => '0' );
MasterData <= ( OTHERS => '0' );
avm_write <= '0';
avm_read <= '0';
avm_byteenable <= ( OTHERS => '0' );
ReadyTmp <= '0';
END IF;
По сигналам CPU_WrEn и CPU_RdEn происходит предварительное защелкивание адреса и данных с процессора во внутренние переменные конечного автомата.
При появлении единицы на линии CPU_RdEn, конечный автомат переходит в состояние FSM_READ — состояние чтения данных по шине Avalon-MM. Процессор должен вместе с единицей на линии CPU_RdEn выставить адрес на входные линии CPU_AddrIn, с которого он запрашивает чтение данных. И в это же время процессор должен задать код на шине CPU_ByteEnCode, чтобы определить, какие байты на шине данных будут активны.
В состоянии FSM_READ конечный автомат дублирует адрес на шину avm_address, повторяет код с CPU_ByteEnCode на линии avm_byteenable и выставляет единицу на линию avm_read, в соответствии с временными диаграммами на рис. 2. В листинге 3 показан исходный код этого состояния на VHDL
Листинг 3. Исходный код реализации состояния FSM_READ
WHEN FSM_READ =>
avm_write <= '0';
avm_read <= '1';
avm_address <= MasterAddr;
avm_byteenable <= CPU_ByteEnCode;
FSM_MasterState <= FSM_ACK_READ;
На следующем такте конечный автомат переходит в состояние FSM_ACK_READ — подтверждение чтения данных. В этом состоянии автомат проверяет значение на линии avm_readdatavalid.
Если значение avm_readdatavalid равно единице, значит на линии avm_readdata доступны верные данные. В таком случае эти данные дублируются на выход CPU_RdDataOut и на линию CPU_Ready выставляется единица, как сигнал для процессора, что c интерфейса Avalon-MM Master доступны новые данные для чтения. На следующем такте автомат переходит в исходное состояние FSM_IDLE.
Если же значение avm_readdatavalid равно нулю, то на линию CPU_Ready выставляется ноль и на следующем такте автомат переходит также в исходное состояние FSM_IDLE.
В листинге 4 представлен исходный код реализации состояния FSM_ACK_READ на VHDL.
Листинг 4. Исхjдный код реализации состояния FSM_ACK_READ
WHEN FSM_ACK_READ =>
IF( avm_readdatavalid = '1' ) THEN
ReadyTmp <= '1';
RdDataOutTmp <= avm_readdata;
FSM_MasterState <= FSM_IDLE;
ELSE
FSM_MasterState <= FSM_IDLE;
ReadyTmp <= '0';
RdDataOutTmp <= ( OTHERS => '0' );
END IF;
Из состояние FSM_IDLE конечный автомат по единице на входной линии CPU_WrEn переходит в состояние FSM_WRITE. В этом состоянии дублируется значение адреса с линии CPU_AddrIn и код с линии CPU_ByteEnCode на выходные линии avm_address и avm_byteenable соответственно. И выставляется единица на линию avm_write. Исходный код реализации этого состояния представлен в листинге 5.
Листинг 5: Исходный код реализации состояния FSM_WRITE.
WHEN FSM_WRITE =>
avm_write <= '1';
avm_read <= '0';
avm_address <= MasterAddr;
avm_byteenable <= CPU_ByteEnCode;
avm_writedata <= MasterData;
FSM_MasterState <= FSM_ACK_WRITE;
На следующем такте автомат переходит в состояние FSM_ACK_WRITE, в котором сбрасывается в 0 сигнал на линии avm_write. Это приводит к завершению операции записи данных в периферийный модуль. Исходный код реализации состояния FSM_ACK_WRITE представлен в листинге 7.
Листинг 7. Исходный код реализации состояния FSM_ACK_WRITE.
WHEN FSM_ACK_WRITE =>
avm_write <= '0';
FSM_MasterState <= FSM_IDLE;
На следующем такте автомат переходит в исходное состояние FSM_IDLE для ожидания новой команды от процессора.
Обработка waitrequest
Конечно не всегда периферийный модуль может за один такт успеть защелкнуть записываемые в него данные либо успеть выдать на следующем такте запрашиваемые в него данные. На этот случай шина Avalon-MM имеет сигнал waitrequest.
Сигнал waitrequest управляется интерфейсом Avalon-MM Slave на периферийном модуле (см. рис. 2). Если периферийный модуль не может в данный момент отреагировать на запрос от Avalon-MM Master, то он выставляет 1 на линию waitrequest. Это приводит к тому, что Avalon-MM Master должен удерживать все сигналы на линии Avalon-MM в текущем состоянии, пока периферийный модуль не сбросить waitrequest в 0. И только тогда Avalon-MM Master сможет завершить текущую операцию записи или чтения.
Обработку сигнала waitrequest лучше всего добавить в состояния FSM_ACK_READ и FSM_ACK_WRITE. Так как в этих состояниях автомат уже выставил все сигналы на шине Avalon-MM, то тут нам только потребуется проверять значения сигнала waitrequest. Пока он равен 1, автомат должен находиться в текущем состоянии, а как только waitrequest будет сброшен в 0, автомат сможет завершить текущую операцию и перейти в состояние FSM_IDLE. Исходные коды реализации состояний FSM_ACK_READ и FSM_ACK_WRITE с обработкой сигнала waitrequest представлены в листинге 8 и 9 соответственно.
Листинг 8. Исходный код реализации сосотяния FSM_ACK_READ с обработкой сигнала waitrequest.
WHEN FSM_ACK_READ =>
IF( avm_readdatavalid = '1' ) THEN
ReadyTmp <= '1';
RdDataOutTmp <= avm_readdata;
avm_read <= '0';
FSM_MasterState <= FSM_IDLE;
ELSE
ReadyTmp <= '0';
RdDataOutTmp <= ( OTHERS => '0' );
IF( avm_waitrequest = '0' ) THEN
IF (wait_cycle > 0) THEN
wait_cycle <= wait_cycle - 1;
ELSE
FSM_MasterState <= FSM_IDLE;
END IF;
ELSE
IF( AckCounter > 0 )THEN
AckCounter := ( AckCounter - 1 );
ELSE
FSM_MasterState <= FSM_IDLE;
END IF;
END IF;
END IF;
Листинг 9. Исходный код реализации сосотяния FSM_ACK_WRITE с обработкой сигнала waitrequest.
WHEN FSM_ACK_WRITE =>
IF( avm_waitrequest = '0' ) THEN
avm_write <= '0';
FSM_MasterState <= FSM_IDLE;
ELSE
IF( AckCounter > 0 )THEN
AckCounter := ( AckCounter - 1 );
ELSE
avm_write <= '0';
FSM_MasterState <= FSM_IDLE;
END IF;
END IF;
Нужно отметить, что в условие проверки сигнала waitrequest полезно добавить счетчик-таймер, по истечению которого, если периферийный модуль так и не сбросит сигнал waitrequest в 0, то автомат вернется в исходное состояние FSM_IDLE. Таким образом возможное зависание периферийного модуля не приведет к зависанию интерфейса Avalon-MM Master.
В нашем случае мы добавили счетчик AckCounter, который считает от 15 до 0. В состоянии FSM_IDLE значение этого счетчика выставляется равное 15.
Так же нужно отметить, что в состояние FSM_ACK_READ была добавилена задержка в 1 такт на счетчике wait_cycle. Это было сделано для того, чтобы автомат задержался в состоянии FSM_ACK_READ на 1 такт дольше, чтобы дождаться появления 1 на линии avm_readdatavalid.
Отладка конечного автомата Avalon-MM Master
Для отладки работы конечного автомата был написан testbench, достаточно простой. Все окружение, кроме тестируемого интерфейса Avalon-MM Master состояло из конечного автомата, который эмулировал команды процессора — FSM_CPU и модуля встроенной памяти On-Chip Memory с интерфейсом Avalon-MM Slave.
Автомат процессора последовательно задавал команды на запись и чтение данных. Встроенная память была изначально проинициализирована тестовыми данными.
На рис. 5 представлены временные диаграммы работы компонента Avalon-MM Master с встроенной памятью через шину Avalon-MM.
Рис. 5 временные диаграммы работы компонента Avalon-MM Master с встроенной памятью через шину Avalon-MM (приставка TB_ обозначает сигналы из testbench)
Когда процессор начинает операцию записи, он выставляет на линии TB_CPU_WrEn, TB_CPU_AddrIN, TB_CPU_WrDataIn соответсвенно сигнал записи, адрес ячейки (0xAD) и данные, которые требуется записать в память (0xDADA0505).
В свою очередь автомат интерфейса Avalon-MM Master переходит в состояние FSM_WRITE и выставляет на шину Avalon-MM сигнал TB_avm_write равный 1 и дублирует адрес и данные на линии TB_avm_address и TB_avm_writedata соответвтенно.
На следующем такте On-Chip Memory выдает 1 на линию TB_waitrequest, сигнализируя о процессе записи данных в память. После чего процедура записи заканчивается. Автомат интерфейса Avalon-MM Master переходит в состояние FSM_IDLE.
Для начала операции чтения процессор выставляет на линии TB_CPU_RdEn интерфейса Avalon-MM Master единицу и на линии TB_CPU_AddrIN адрес ячейки (0xBB) для чтения данных.
Автомат интерфейса Avalon-MM Master переходит в состояние FSM_READ и выставляет единицу на линии TB_avm_read, а так же дублирует адрес ячейки на шину адреса TB_avm_address и выставляет код активных байтов (0xF) на линии TB_avm_byteenable.
На следующем такте On-Chip Memory выдает 1 на линию TB_waitrequest, сигнализируя о процессе чтения данных из памяти. И в следюущий такт считаные данные выставыляются на линию TB_avm_readdata (0×1A2B3C4D) и одновременно с этим выставляется единица на линию TB_avm_readdatavalid, сигнализирующая, что выставлены валидные данные. После чего автомат интерфеса Avalon-MM Master выставляет единицу на линию TB_CPU_Ready, показывая что доступны новые данные для процессора и дублирует данные с линии TB_avm_readdata на выход TB_CPU_RdDataOut. После чего операция чтения завершается.
Заключение
В данной статье был рассмотрен вариант реализации конечного автомата для интерфейса Avalon-MM Master. Данная реализация позволяет встраивать этот интерфейс в свои компоненты, что приводит к повышению степени их повторного использования и упрощает проектирование систем на ПЛИС с использованием инструмента Platform Designer.