Transaction Level Modeling в SystemC
Адам Роз, Mentor Graphics; Стюарт Сван, Джон Пирс, Жан-Михаил Фернандез, Cadence Design Systems
Источник: http://www.systemc.org/ (Требуется регистраиця)
Краткий обзор
Во введении описана причина, по которой мы решили предложить использование стандарта Transaction Level Modeling. В данном разделе мы сосредоточились на основных случаях использования технологии и увеличения производительности. В разделе 2 подробно описано ядро tlm. Раздел 3 показывает обработку single master / single slave в отличие от технологии rtl. В разделе 4 рассмотрено, как создать объекты TLM типа централизованных маршрутизаторов, арбитров, каналов, и децентрализованного использования схем расшифровки. Раздел 5 показывает, как объединять основные компоненты из раздела 4, для исследования и создания различных видов переключателей.
В первом приложении рассмотрены примеры использования sc_export. Во втором приложении кратко рассмотрены некоторые основные эффективные и безопасные принципы использования OSCI TLM в среде SystemC. В заключительном приложении приведен список всех интерфейсов tlm.
Исходные коды примеров, содержащиеся в данном документе доступны в OSCI TLM комплекте на сайте
www.systemc.org.
1. Введение
Создание технологии Transaction Level Modeling (TLM) мотивировано множеством практических проблем. Они включают:
старые платформы для создания программного обеспечения;
исследования проектов и их проверка;
потребность использовать моделей при блочном тестировании устройств.
Принятие стандарта TLM помогло бы увеличить производительность разработчиков программного обеспечения, архитекторов, инженеров, занимающихся проверкой цифровых устройств. Однако, увеличение производительности, обещанное этим стандартом, может быть достигнуто при условии выполнения следующих критериев:
использование в параллельных системах должно быть легким, эффективным и безопасным;
должно быть возможно использование идентичных объектов в разных проектах и объектов разного
уровня абстракции в одном проекте;
должно быть легко моделировать цифровые устройства, программное обеспечение и проекты, которые включают в себя и то и другое;
должны быть включены основные компоненты, такие как маршрутизаторы и арбитры.
Начиная с выхода версии 2.0, стало возможным использовать TLM в SystemC. Однако, нехватка установленных стандартов и методологий означала, что каждое изменение TLM должно было привести к изменению методологии и API. В дополнение, все эти методологии отличались между собой, делая затруднительным обмен данными с помощью IP сетей.
Этот документ покажет соответствие предложенного OSCI TLM стандарта всем требованиям, описанным выше, и продемонстрирует, как использовать его, чтобы решить различные проблемы моделирования. Мы полагаем, что широкое распространение и принятие этого стандарта приведет к увеличению производительности благодаря технологии TLM.
2. Предложение TLM
2.1 Ключевые Понятия
Есть три ключевых понятия, которые нужно понять для понимания всей технологии TLM.
2.1.1 Интерфейсы
Акцент стоит на интерфейсах, а не на реализации, потому как SystemC является C++ библиотекой, а C++ (при использовании должным образом) является объектно-ориентированным языком. Сначала мы должны строго определить ключевые интерфейсы, а лишь затем продолжить обсуждение различных способов, с помощью которых они могут быть осуществлены в проекте TLM. Важно понять, что классы интерфейсов TLM формируют основу стандарта TLM, и что выполнение тех или иных интерфейсов (например tlm_fifo) не является столь важным. В SystemC, все интерфейсы должны наследоваться от класса sc_interface.
2.1.2 Блокируемые и неблокируемые интерфейсы
В SystemC есть два основных вида процессов: SC_THREAD и SC_METHOD. Ключевое различие между этими двумя - то, что возможно приостановить выполнение процесса SC_THREAD запросом wait(.). SC_METHODs с другой стороны может быть синхронизирован, но это делает его чувствительным к внешним событиям, определенным в sc_event. Вызов wait(.) в SC_METHOD приведет к ошибке во время выполнения программы. Использование SC_THREAD в различных ситуациях более естественно, но медленнее, потому как wait(.) вызывает переключение на другой процесс в планировщике SystemC. Используя SC_METHOD более ограниченно, но более эффективно, потому как при его использовании не требуется переключение[2].
Поскольку возникнет ошибка при вызове wait изнутри SC_METHOD, каждый метод должен явно указывать, возможен ли вызов данной функции. Поэтому метод должен быть вызван из SC_THREAD, в ином случае из SC_METHOD. OSCI стандарт использует терминологию "блокируемый интерфейс" для первого случая и "неблокируемый" для второго.
OSCI TLM стандарт строго придерживается OSCI терминологии "блокируемые" и "неблокируемые". К примеру, если интерфейс TLM помечен как "неблокируемый", то его методы никогда не смогут вызвать wait().
OSCI Терминология |
Содержит wait(.) |
Возможно вызвать из |
Блокируемый |
Возможно |
только SC_THREAD |
Неблокируемый |
Нет |
SC_METHOD или SC_THREAD |
2.1.3 Двунаправленная и однонаправленная передача данных
Некоторые обычные транзакции явно двунаправлены, например считывание данных с шины. Другие транзакции явно однонаправлены. В случае более сложного протокола всегда возможно разделить передачу данных на двунаправленную или однонаправленную. Например, сложная шина с адресом. Управление и фазы данных могут быть схожи с шиной чтения/записи на высшем уровне абстракции, но это можно представить как последовательность однонаправленных каналов на более детализированном уровне. Любой стандарт TLM должен иметь и двунаправленные и однонаправленные интерфейсы. Стандарт должен иметь стандартный вид и явно показывать взаимоотношения между этими интерфейсами.
2.2 Основные интерфейсы TLM
2.2.1 Однонаправленные интерфейсы
Однонаправленные интерфейсы основаны на интерфейсах sc_fifo, как описано в стандарте SystemC 2.1. Sc_fifo использовался множество лет во многих типах моделирования, так как критическим параметром во многих проектах является размер fifo. В результате fifo интерфейсы легки для понимания, и мы знаем, что они являются надежными в параллельных системах. Еще одно преимущество использования интерфейсов, основанных на sc_fifo, состоит в том, что будущие симуляторы в состоянии выполнить известную статическую оптимизацию планирования. В дополнение к этому, классы интерфейсов разделены на блокируемые, и неблокируемые классы. Неблокируемые методы отличаются от блокируемых приставкой "nb_".
Однако, для TLM мы имеем новые требования
Требуется некоторое значение свободной терминологии, так как "read" и "write" в текущих интерфейсах sc_fifo
очень загружено в контексте TLM
Эти интерфейсы должны быть включены в fifo как другой канал или непосредственно конечный объект,
используя sc_export.
Чтобы решить первую из этих проблем, мы перемещаем данные от инициатора к цели, назовем это "put" и когда мы передаем
данные от цели до инициатора, мы называем это "get".
Последствие второго требования - то, что мы должны добавить tlm_tag к некоторым из интерфейсов. Это - C ++ уловка,
которая позволит нам создать более чем одну версию интерфейса в одном классе, если параметры шаблона интерфейсов различны.
Третье требование будет выполнено при введении блокируемых, неблокируемых и комбинированных интерфейсов.
2.2.2 Однонаправленные блокируемые интерфейсы
template < typename T >
class tlm_blocking_get_if :
public virtual sc_interface
{
public:
virtual T get( tlm_tag *t = 0 ) = 0;
virtual void get( T &t ) { t = get(); }
};
template < typename T >
class tlm_blocking_peek_if :
public virtual sc_interface
{
public:
virtual T peek( tlm_tag *t = 0 ) = 0;
virtual void peek( T &t ) { t = peek(); }
};
template < typename T >
class tlm_blocking_put_if :
public virtual sc_interface
{
public:
virtual void put( const T &t ) = 0;
};
Так как мы можем использовать функцию wait в блокируемых интерфейсах, никогда не возникнет ошибки. Для удобства, мы создали два метода get и peek, хотя, в большинстве случаев требуется только один.
2.2.3 Однонаправленные неблокируемые интерфейсы
template < typename T >
class tlm_nonblocking_get_if :
public virtual sc_interface
{
public:
virtual bool nb_get( T &t ) = 0;
virtual bool nb_can_get( tlm_tag *t = 0 ) const = 0;
virtual const sc_event &ok_to_get( tlm_tag *t = 0 ) const = 0;
};
template < typename T >
class tlm_nonblocking_get_if :
public virtual sc_interface
{
public:
virtual bool nb_peek( T &t ) = 0;
virtual bool nb_can_peek( tlm_tag *t = 0 ) const = 0;
virtual const sc_event &ok_to_peek( tlm_tag *t = 0 ) const = 0;
};
template < typename T >
class tlm_nonblocking_put_if :
public virtual sc_interface
{
public:
virtual bool nb_put( const T &t ) = 0;
virtual bool nb_can_put( tlm_tag *t = 0 ) const = 0;
virtual const sc_event &ok_to_put( tlm_tag *t = 0 ) const = 0;
};
В неблокируемых интерфейсах может возникнуть ошибка, так как невозможно использовать функцию wait, следовательно, невозможно дождаться определенного состояния. Таким образом nb_put, nb_get и nb_peek должны возвращать bool значение, чтобы возможно было узнать когда будет доступен неблокируемый интерфейс. Существуют также методы nb_can_put, nb_can_get и nb_can_peek для того, чтобы узнать будет ли транзакция успешной.
Этих методов достаточно, чтобы осуществлять опрос методов put, get и peek. Также существуют функции, которые позволяют SC_THREAD ожидать определенного события или SC_METHOD, который будет инициирован при регистрации события. Ожидание событий позволяет прервать выполнение неблокируемого интерфейса. Однако, в общем случае, даже если требуемое событие было зарегистрировано, мы все равно должны проверить возможность использования интерфейса.
2.2.4 Двунаправленные блокируемые интерфейсы
template
class tlm_transport_if : public sc_interface
{
public:
virtual RSP transport(const REQ&) = 0;
};
Двунаправленные блокируемые интерфейсы используется для моделирования транзакций, когда соединены два объекта непосредственно друг с другом без использования других каналов связи. Данный подход является верным с точки зрения разработчиков программного обеспечения, когда, например, на вход передается адрес данных, а на выход отсылаются прочитанные данные.
Структура функции transport может быть описана как сочетание get и put функций. Таким образом, мы можем создать интерфейс tlm_transport_if, который просто вызывает соответствующие функции put(.) и get(.) из двух однонаправленных интерфейсов.
2.3 Каналы TLM
Один или более интерфейсов, описанных выше, могут быть реализованы в любом канале, который требуется спроектировать или непосредственно объектах, используя sc_export. Однако три этих канала являются наиболее используемыми и включены в SystemC как основные классы.
2.3.1 tlm_fifo
Шаблонный класс tlm_fifo включает все однонаправленные интерфейсы, описанные выше. Реализация данного канала fifo основано на реализации sc_fifo. Данные, помещенные в tlm_fifo, недоступны для считывания пока не будет выполнен следующий цикл. В дополнение к функциональным возможностям sc_fifo, tlm_fifo, размер данных может быть нолем или бесконечностью. Данные возможности подробнее рассмотрены в пункте в 4.3.1.
2.3.2 tlm_req_rsp_channel< REQ,RSP >
Класс tlm_req_rsp_channel< REQ, RSP > состоит из двух fifo - один для получения данных от инициатора и передачи к цели, второй, для передачи данных от цели до инициатора. Для обеспечения прямого доступа к этим fifo инициатор и цель экспортируют интерфейсы put и get.
Для удобства, они сгруппированы в интерфейсы master и slave, как показано ниже:
template < typename REQ , typename RSP >
class tlm_master_if :
public virtual tlm_extended_put_if< REQ > ,
public virtual tlm_extended_get_if< RSP > {};
template < typename REQ , typename RSP >
class tlm_slave_if :
public virtual tlm_extended_put_if< RSP > ,
public virtual tlm_extended_get_if< REQ > {};
};
Все fifo в tlm_req_rsp_channel могут иметь произвольный размер.
2.3.3 tlm_transport_channel< REQ, RSP >
tlm_transport_channel используется для моделирования ситуации, в которых каждый запрос явно зависит от возвращаемых данных. Поэтому все fifo должны быть одинакового размера. tlm_transport_channel так же экспортирует те же самые интерфейсы, что и tlm_req_rsp_channel, но включает в себя двунаправленный интерфейс как показано ниже:
RSP transport( const REQ &req ) {
RSP rsp;
mutex.lock();
request_fifo.put( req );
response_fifo.get( rsp );
mutex.unlock();
return rsp;
}
Эта простая функция обеспечивает ключевую связь между двунаправленными и последовательными интерфейсами
как показано в transport и однонаправленными интерфейсами, как показано в tlm_fifo. Более подробно это будет рассмотрено
в главах, посвященных примерам реализации интерфейсов transactor (3.4) и arbiter (4.2).
2.4 Вывод
Методы и классы, описанные в главе 2.2, показывают основные возможности OSCI TLM. На основе этого простого транспортного механизма, мы можем строить модели программного обеспечения и аппаратных средств, маршрутизаторов и арбитров, шин с различным типом каналов и пакеты основных протоколов. Мы можем моделировать на различных уровнях абстракции и с помощью каналов соединять их. Поскольку они основаны на интерфейсах к sc_fifo, они легко поняты, безопасны и эффективны.
Пользователи могут проектировать собственные каналы передачи данных, используя реализацию некоторых из этих интерфейсов, или они могут добавлять их непосредственно в объекты, используя sc_export. Функция transport особенно полезна, когда требуется быстро создать прототип модели программного обеспечения.
В дополнение к основным интерфейсам, мы определили три стандартных канала, tlm_fifo< T >, tlm_req_rsp_channel< REQ, RSP > и tlm_transport_channel< REQ, RSP >. Эти три канала могут использоваться, чтобы моделировать разнообразные системы. С помощью класса tlm_transport_channel возможно создание удобной связи между синхронными и асинхронными областями.
|