Проектирование микропроцессорных ядер с использованием приложения StateFlow системы MATLAB/Simulink

№ 1’2010
Данная статья продолжает цикл работ по использованию возможностей системы визуально-имитационного моделирования MATLAB/Simulink для проектирования микропроцессорных ядер для реализации в базисе ПЛИС.

Основная идея этой работы — заменить описание управляющего автомата (M-файл, табл. 1) микропроцессорного ядра из [1, 2] визуально-графическим автоматом (граф переходов), построенным с помощью приложения (пакет расширения) StateFlow системы MATLAB/Simulink. Далее с помощью приложения Simulink HDL Coder сгенерировать код языка VHDL и затем реализовать модель микропроцессора в базисе ПЛИС Stratix III EP3SL50F484C2 фирмы Altera. Особенностью данного типа ПЛИС семейства Stratix III является структура памяти TriMatrix с рабочими тактовыми частотами до 600 МГц, которая содержит 108 блоков памяти типа M9K (емкость блока — 9216 бит), 6 блоков памяти типа M144K (емкость — 147 456 бит) и 950 блоков памяти MLAB (емкость — 320 бит). Общий объем встроенной памяти ОЗУ — 1836 кбит, 475 К логических элементов (LE), 19 К адаптивных логических модулей (ALM), которые способны работать в различных режимах, и 38 К триггеров.

В таблице 1 приведен M-файл и код управляющего автомата на языке VHDL из [2]. Видно, что по M-файлу сгенерирован асинхронный цифровой автомат с использованием двух операторов выбора CASE, представляющий собой комбинационный дешифратор.

Таблица 1. M-файл и код управляющего автомата на языке VHDL [2]

Как и в работе [2], процессор состоит из следующих блоков (рис. 1): ROM — ПЗУ команд процессора (память программ); COP — блок выделения полей команды (дешифратор команд); ALU — 8-разрядное АЛУ процессора (управляющий автомат); RON — блок регистров общего назначения (8-разрядные регистры А и B); RSN — блок регистров специального назначения, 8-разрядный регистр R (стек команд) для обеспечения выполнения команд обращения к подпрограммам (CALL) и возврата (RET) и 8-разрядный регистр Ip (для хранения значений счетчика команд). На рис. 1 также показана тестовая программа (содержимое файла прошивки ПЗУ такое же, как и в [3]) и система команд из [1].

Рис. 1. Модель микропроцессорного ядра с управляющим автоматом в системе MATLAB/Simulink

Для построения ПЗУ используется функциональный блок Lookup Table (таблица соответствия). Все сигналы в процессоре представлены в формате uint8 (Unsigned integer fixed-point data type, целые числа без знака в формате с фиксированной запятой, с 8-битной шиной), кроме команд (сигналы cmd и InCmd), они представлены в формате uint16.

Управляющий автомат микропроцессора разработан с помощью приложения StateFlow (рис. 2). StateFlow является интерактивным инструментом разработки в области моделирования сложных, управляемых событиями систем. Он тесно интегрирован с MATLAB и Simulink и основан на теории конечных автоматов. Диаграмма StateFlow — графическое представление конечного автомата, где состояния и переходы формируют базовые конструктивные блоки проектируемой системы.

Рис. 2. Управляющий автомат (блок АЛУ), созданный с помощью приложения StateFlow в режиме отладки

StateFlow-диаграмма построена из отдельных объектов, таких как состояние, переход, переход по умолчанию и др. Более подробную информацию можно найти в [4]. Состояние — условие, в котором моделируемая система пребывает некоторое время, в течение этого времени она ведет себя одинаковым образом. В диаграмме переходов состояния представлены прямоугольными полями со скругленными углами. Например, состояние COMM является родителем состояний MOVAB, RET, MOVBA, XCHG, ADD, SUB, END, OR, XOR, DEC. На рис. 3 показаны временные диаграмы работы модели микропроцессорного ядра в системе MATLAB/ Simulink; A, B, R, IP — выходы соответствующих регистров РОН и РСН.

Рис. 3. Временные диаграммы работы модели микропроцессорного ядра в системе MATLAB/Simulink

Переход — это линия со стрелкой, соединяющая один графический объект с другим. В большинстве случаев переход представляет собой скачок системы из одного режима (состояния) в другой. Переход соединяет объект-источник с объектом-адресатом. Объект-источник — это место, где переход начинается, объект-адресат — это место, где переход заканчивается. Переходы по состояниям характеризуются метками. Метка может включать в себя имя события, условие, действие условия и/или действие перехода. Первоначально переходы помечаются символом «?». Метки перехода имеют следующий основной формат: event [condition] {condition_action} / transition_action. Любая часть метки может отсутствовать. Условия — это булевы выражения, которые должны быть истинны для осуществления перехода. Условия заключаются в квадратные скобки — []. Например, условие [InA= =0] должно быть истинным для того, чтобы произошло действие условия и переход стал возможен.

Действия условий следуют за условиями и заключаются в фигурные скобки — {}. Они выполняются тогда, когда условие становится истинным, но перед тем, как переход осуществится. Если ни одно условие не определено, подразумеваемое условие принимается за истинное и действие выполняется. Если условие [InA= =0] истинно, то действие {OutIP=InData} немедленно выполняется.

Линия со стрелкой и точкой на конце — это безусловный переход. Безусловные переходы преимущественно используются для определения, какое последовательное состояние должно стать активным, когда есть неоднозначность между двумя или более ИЛИ-подсостояниями. Безусловные переходы имеют объект-адресат, но у них нет объекта-источника.

На рис. 4 показано микропроцессорное ядро с асинхронным ПЗУ в базисе ПЛИС Stratix III в САПР Quartus II, код языка которого получен с использованием Simulink HDL Coder системы MATLAB/Simulink. ПЗУ, дешифратор команд — комбинационные устройства, регистры RON, RSN и управляющий автомат (ALU) — синхронные последовательностью устройства.

Рис. 4. Микропроцессорное ядро с асинхронным ПЗУ и синхронным управляющим автоматом в базисе ПЛИС Stratix III в САПР ПЛИС Quartus II, код языка которого получен с использованием Simulink HDL Coder системы MATLAB/Simulink

Для описания управляющего автомата микропроцессора (пример) используются перечислимые типы. Перечислимый тип часто применяется для обозначения состояний конечных автоматов [3]. Анализируя код VHDL, можно сделать вывод, что сгенерирован синхронный автомат с асинхронным входом Reset (активный — высокий уровень) и с синхронным сигналом разрешения тактирования clk_enable. Функциональное моделирование работы микропроцессорного ядра с асинхронным ПЗУ и синхронным управляющим автоматом в базисе ПЛИС Stratix III показано на рис. 5.

Рис. 5. Функциональное моделирование работы микропроцессорного ядра с асинхронным ПЗУ и синхронным управляющим автоматом в базисе ПЛИС Stratix III

Для сравнения на рис. 6 показано функциональное моделирование работы микропроцессорного ядра из работы [2] с асинхронным ПЗУ и асинхронным управляющим автоматом в базисе ПЛИС Stratix III.

Рис. 6. Функциональное моделирование работы микропроцессорного ядра из работы [2] с асинхронным ПЗУ и асинхронным управляющим автоматом в базисе ПЛИС Stratix III

Видно, что микропроцессорные ядра работают одинаково, но для микропроцессора с синхронным автоматом требуется большее число тактов на отработку команд, и по-разному выполняется команда с кодом 0600H (RET). На StateFlow-диаграмме можно по-иному организовать выполнение команды вызова и возврата из подпрограммы. Для команды CALL: OutR=InIP и команды RET: OutIP=InR. Сведения по используемым ресурсам ПЛИС представлены в таблице 2.

Таблица 2. Используемые ресурсы ПЛИС Stratix III EP3SL50F484C2

Логические ресурсы

Максимальная
Проект Адаптивные таблицы перекодировок ALUT, для реализации комбинационных функций выделенные триггеры логических элементов тактовая частота синхросигнала, ‘maxCLI Мгц
Асинхронное ПЗУ, асинхронный управляющий автомат (M-файл) 82 26 360
Асинхронное ПЗУ, синхронный управляющий автомат (StateFlow) 103 59 275

LIBRARY ieee;

USE ieee.std_logic_1164.all;

USE ieee.numeric_std.all;

ENTITY ALU IS PORT (

clk : IN std_logic; clk_enable : IN std_logic; reset : IN std_logic;

InCmd : IN std_logic_vector(7 DOWNTO 0); InData : IN std_logic_vector(7 DOWNTO 0); InIP : IN std_logic_vector(7 DOWNTO 0); InR : IN std_logic_vector(7 DOWNTO 0); InA : IN std_logic_vector(7 DOWNTO 0); InB : IN std_logic_vector(7 DOWNTO 0); OutIP : OUT std_logic_vector(7 DOWNTO 0); OutR : OUT std_logic_vector(7 DOWNTO 0); OutA : OUT std_logic_vector(7 DOWNTO 0); OutB : OUT std_logic_vector(7 DOWNTO 0));

END ALU;

ARCHITECTURE fsm_SFHDL OF ALU IS

TYPE T_state_type_is_ALU is (IN_NO_ACTIVE_CHILD, IN_CALL, IN_COMM, IN_INST, IN_JMP, INJMPZ, IN_MOVA, IN_MOVB, IN_NOP, IN_ReadInst);

TYPE T_state_type_is_COMM is (IN_NO_ACTIVE_CHILD, IN_ADD, IN_AND, IN_DEC, IN_MOVAB, IN_MOVBA, IN_OR, IN_RET, IN_SUB, IN_XCHG, IN_XOR); SIGNAL is_ALU : T_state_type_is_ALU; SIGNAL is_COMM : T_state_type_is_COMM; SIGNAL OutIP_reg : unsigned(7 DOWNTO 0); SIGNAL OutR_reg : unsigned(7 DOWNTO 0); SIGNAL OutA_reg : unsigned(7 DOWNTO 0); SIGNAL OutB_reg : unsigned(7 DOWNTO 0); SIGNAL is_ALU_next : T_state_type_is_ALU; SIGNAL is_COMM_next : T_state_type_is_COMM; SIGNAL OutIP_reg_next : unsigned(7 DOWNTO 0); SIGNAL OutR_reg_next : unsigned(7 DOWNTO 0); SIGNAL OutA_reg_next : unsigned(7 DOWNTO 0); SIGNAL OutB_reg_next : unsigned(7 DOWNTO 0);

BEGIN

irntialize_ALU : PROCESS (reset, clk)

— local variables BEGIN

IF reset = ‘1’ THEN

is_COMM <= IN_NO_ACTIVE_CHILD; OutIP_reg <= to_unsigned(0, 8); OutR_reg <= to_unsigned(0, 8); OutA_reg <= to_unsigned(0, 8); OutB_reg <= to_unsigned(0, 8); is_ALU <= IN_ReadInst; ELSIF clk’EVENT AND clk= ‘1’ THEN IF clk_enable= ‘1’ THEN is_ALU <= is_ALU_next; is_COMM <= is_COMM_next; OutIP_reg <= OutIP_reg_next; OutR_reg <= OutR_reg_next; OutA_reg <= OutA_reg_next; OutB_reg <= OutB_reg_next; END IF;

END IF; END PROCESS imtialize_ALU;

ALU : PROCESS (is_ALU, is_COMM, OutIP_reg, OutR_reg, OutA_reg, OutB_reg, InCmd, InData, InIP, InR, InA, InB) — local variables BEGIN

is_ALU_next <= is_ALU; is_COMM_next <= is_COMM; OutIP_reg_next <= OutIP_reg; OutR_reg_next <= OutR_reg; OutA_reg_next <= OutA_reg; OutB_reg_next <= OutB_reg; CASE is_ALU IS

WHEN IN_CALL =>

is_ALU_next <= IN_ReadInst; WHEN IN_COMM =>

is_COMM_next <= IN_NO_ACTIVE_CHILD; is_ALU_next <= IN_INST; OutIP_reg_next <= unsigned(InIP) + 1; WHEN IN_INST =>

is_ALU_next <= IN_ReadInst; WHEN IN_JMP =>

is_ALU_next <= IN_ReadInst; WHEN IN_JMPZ =>

IF unsigned(InA) = 0 THEN

OutIP_reg_next <= unsigned(InData); is_ALU_next <= IN_ReadInst; ELSIF unsigned(InA) /= 0 THEN is_ALU_next <= IN_INST; OutIP_reg_next <= unsigned(InIP) + 1; END IF; WHEN IN_MOVA =>

is_ALU_next <= IN_INST; OutIP_reg_next <= unsigned(InIP) + 1; WHEN IN_MOVB =>

is_ALU_next <= IN_INST; OutIP_reg_next <= unsigned(InIP) + 1; WHEN IN_NOP =>

is_ALU_next <= IN_INST; OutIP_reg_next <= unsigned(InIP) + 1; WHEN IN_ReadInst =>

IF unsigned(InCmd) = 6 THEN is_ALU_next <= IN_COMM; IF unsigned(InData) = 1 THEN is_COMM_next <= IN_MOVAB; OutA_reg_next <= unsigned(InB); ELSIF unsigned(InData) = 0 THEN is_COMM_next <= IN_RET; OutIP_reg_next <= unsigned(InR) — 1; ELSIF unsigned(InData) = 3 THEN is_COMM_next <= IN_XCHG; OutA_reg_next <= unsigned(InB); OutB_reg_next <= unsigned(InA); ELSIF unsigned(InData) = 2 THEN is_COMM_next <= IN_MOVBA; OutB_reg_next <= unsigned(InA); ELSIF unsigned(InData) = 4 THEN is_COMM_next <= IN_ADD;

OutA_reg_next <= unsigned(InA) + unsigned(InB); ELSIF unsigned(InData) = 5 THEN is_COMM_next <= IN_SUB; OutA_reg_next <= unsigned(InA) — unsigned(InB); ELSIF unsigned(InData) = 6 THEN is_COMM_next <= IN_AND; OutA_reg_next <= unsigned(InA AND InB); ELSIF unsigned(InData) = 7 THEN is_COMM_next <= IN_OR; OutA_reg_next <= unsigned(InA OR InB); ELSIF unsigned(InData) = 8 THEN is_COMM_next <= IN_XOR; OutA_reg_next <= unsigned(InA XOR InB); ELSIF unsigned(InData) = 9 THEN is_COMM_next <= IN_DEC; OutA_reg_next <= unsigned(InA) — 1; END IF;

ELSIF unsigned(InCmd) = 5 THEN is_ALU_next <= IN_MOVB; OutB_reg_next <= unsigned(InData); ELSIF unsigned(InCmd) = 4 THEN is_ALU_next <= IN_MOVA; OutA_reg_next <= unsigned(InData); ELSIF unsigned(InCmd) = 3 THEN is_ALU_next <= IN_CALL; OutR_reg_next <= unsigned(InIP) + 1; OutIP_reg_next <= unsigned(InData); ELSIF unsigned(InCmd) = 2 THEN

is_ALU_next <= IN_JMPZ; ELSIF unsigned(InCmd) = 1 THEN is_ALU_next <= IN_JMP; OutIP_reg_next <= unsigned(InData); ELSIF unsigned(InCmd) = 0 THEN

is_ALU_next <= IN_NOP; END IF; WHEN OTHERS =>

is_ALU_next <= IN_ReadInst; END CASE; END PROCESS ALU;

OutIP <= std_logic_vector(OutIP_reg_next); OutR <= std_logic_vector(OutR_reg_next); OutA <= std_logic_vector(OutA_reg_next); OutB <= std_logic_vector(OutB_reg_next); END fsm_SFHDL;

Пример. Код языка VHDL управляющего автомата модели микропроцессорного ядра на StateFlow, полученный с использованием Simulink HDL Coder системы MATLAB/Simulink

Выводы

Приложение Simulink HDL Coder для управляющего автомата микропроцессора построенного с помощью StateFlow системы MATLAB/Simulink, позволяет сгенерировать код языка VHDL синхронного автомата.

Система визуально-имитационного моделирования MATLAB/Simulink с приложениями StateFlow и Simulink HDL Coder может быть эффективно использована для ускоре

ния процесса разработки моделей микропроцессорных ядер. Проект микропроцессора с асинхронным ПЗУ на языке VHDL может быть успешно размещен в ПЛИС Stratix III EP3SL50F484C2, при этом общее число задействованных логических ресурсов составляет менее 1%.

Литература

  1. Тарасов И. Проектирование конфигурируемых процессоров на базе ПЛИС. Часть II // Компоненты и технологии. 2006. № 3.
  2. Строгонов А., Буслов А. Проектирование учебного процессора для реализации в базисе ПЛИС с использованием системы MATLAB/Simulink // Компоненты и технологии. 2009. № 5.
  3. Строгонов А., Цыбин С. Использование различных типов памяти при проектировании учебного микропроцессорного ядра для реализации в базисе ПЛИС // Компоненты и технологии. 2009. № 12.
  4. Рогачев Г. Н. Stateflow 5.0. Руководство пользователя: www.exponenta.ru.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *