Руководство программиста
Глава 1. Устройство RDS
§1.5. Статические переменные блоков, входы и выходы
Описывается структура и возможные типы статических переменных блока, то есть тех переменных, которые обычно существуют все время жизни блока и не создаются и не уничтожаются в процессе работы схемы. Входы и выходы блока, к которым могут присоединяться связи, всегда являются статическими переменными. Описывается способ формирования строки типа, используемой для проверки правильности структуры переменных.
Статические переменные, в основном, служат для подключения связей к блоку, а также для хранения параметров, которые создатель модели блока решил не размещать в личной области данных. Для простых блоков они, чаще всего, задаются при создании блока и указании его модели, после чего их структура уже не изменяется. Редактор переменных (рис. 9) вызывается кнопкой «» вкладки «» окна параметров блока (рис. 8). В памяти эти переменные расположены друг за другом, поэтому, зная указатель на область переменных и размер каждой из них в памяти, модель может обращаться к различным переменным по фиксированным смещениям. Для простых переменных (целые и вещественные числа, логические значения) в памяти хранятся сами значения, а для сложных, размер которых может изменяться (массивы, матрицы, переменные произвольного типа), в памяти хранится указатель на область памяти, занимаемой сложной переменной. Таким образом, при наличии у блока сложных переменных, область переменных представляет собой дерево, поэтому набор статических переменных блока обычно называется деревом переменных.
Рис. 8. Параметры блока – переменные
Рис. 9. Редактор переменных
Каждая статическая переменная имеет имя, уникальное в данном блоке – оно задается в колонке «» редактора (см. рис. 9). Для того, чтобы имена переменных блоков можно было использовать в программах их моделей, они должны подчиняться правилам, принятым в большинстве языков программирования: имя переменной должно содержать только буквы латинского алфавита, цифры и знак подчеркивания, и при этом оно не должно начинаться с цифры. Имена переменных чувствительны к регистру, поэтому, например, «Start» и «start» будут считаться разными переменными.
Переменные в RDS могут быть одного из следующих типов, выбираемых в колонке «» редактора переменных:
- Сигнал (размер – 1 байт)
- Сигналы служат для передачи информации о наступлении какого-либо события, и могут принимать два значения: 1 (событие наступило) и 0 (событие не наступило). Сигнал передается по связи только в том случае, если значение выхода блока, от которого отходит эта связь, равно 1. После передачи значение выхода сбрасывается в 0, таким образом блокируется повторная передача информации о том же самом событии. Блок, обнаруживший на сигнальном входе единицу, должен сам сбросить ее в 0, чтобы подготовится к приему информации о следующем событии. Первая переменная простого блока всегда является сигнальным входом (обычно она называется «Start»), появление единицы в котором в режиме расчета приводит к запуску модели блока, а вторая переменная – сигнальным выходом («Ready»), единица в котором активизирует передачу данных с выходов блока.
- Логический (размер – 1 байт)
- Логические переменные могут принимать одно из двух значений: 0 (ложь) и 1 (истина).
- char (размер – 1 байт)
- Целая однобайтовая переменная, предназначенная для хранения небольших целых чисел (диапазон значений: −128 … 127) или кодов символов, полностью эквивалентная типу signed char в C++. Этот тип используется в блоках редко, в основном, для совместимости со старыми моделями. Для работы с целыми числами чаще всего используется тип int.
- short (размер – 2 байта)
- Целая двухбайтовая переменная с диапазоном значений −32768 … 32767, эквивалентная типу short int в C++. В настоящее время используется редко.
- int (размер – 4 байта)
- Целая четырехбайтовая переменная с диапазоном значений −2147483648 … 2147483647. Основной тип для работы с целыми числами в RDS. Эквивалентен тридцатидвухбитному типу int в C++.
- float (размер – 4 байта)
- Вещественная переменная одинарной точности с диапазоном значений модуля числа 1.18×10−38 … 3.40×1038. Этот тип эквивалентен одноименному типу в C++. Используется редко.
- double (размер – 8 байтов).
- Вещественная переменная двойной точности с диапазоном значений модуля числа 2.23×10−308 … 1.79×10308. Этот тип эквивалентен одноименному типу в C++, он используется во всех стандартных блоках для работы с вещественными числами.
- Строка (размер – 8 байтов).
- Содержит указатель на строку символов произвольной длины, завершающуюся кодом 0. Если строка пустая, может содержать нулевой указатель (NULL). В строках RDS всегда используется кодировка UTF8. Работа со строками в модели блока рассматривается в §2.5.4.
- Массив / матрица (размер – 16 байтов)
- Первые 8 байтов переменной содержат указатель на область данных массива или матрицы или нулевой указатель (NULL) при отсутствии элементов. Вторые 8 байтов – служебные, они используются RDS для определения типа элемента массива. Область данных матрицы содержит число строк и столбцов (первые и вторые 4 байта соответственно), за которыми следуют последовательно записанные данные элементов. Массив отличается от матрицы только тем, что при указании номера элемента используется только один индекс (второй считается нулевым). Область данных массива ничем не отличается от области данных матрицы (в качестве числа строк всегда хранится значение 1). Работа с массивами и матрицами в модели блока рассматривается в §2.5.3.
- Произвольный тип (размер – 16 байтов)
- Универсальный тип переменной, который может изменяться в процессе работы блока. К входам произвольного типа можно подключать связи от выходов любого типа – в момент срабатывания связи такой вход получит тот же фактический тип, что и выход, передавший ему значение. Выход произвольного типа может подстраиваться под разные типы значений при работе модели блока. Первые 8 байтов переменной содержат указатель на область данных переменной, вторые 8 байтов – служебные, используются RDS для хранения текущего фактического типа переменной. Переменные произвольного типа обрабатываются RDS медленнее, чем другие, поэтому их следует использовать только для данных, тип которых заранее неизвестен (например, при создании моделей универсальных мультиплексоров или демультиплексоров). Работа с переменными произвольного типа в модели блока рассматривается в §2.5.6.
- Структура (размер – 8 байтов)
- Содержит указатель на область памяти, в которой последовательно размещены значения полей структуры. Каждое поле – это отдельная переменная, имеющая собственные имя и тип. Связи могут подключаться как к структуре в целом, так и к ее отдельным полям. У структуры есть имя типа – произвольная строка, связанная с данным конкретным набором полей. Структуры чаще всего используются для работы со сложными данными, состав их полей может редактироваться пользователем. Работа со структурами в модели блока рассматривается в §2.5.5.
Статические переменные блока могут быть внутренними, входами или выходами – их роль задается в колонке «» редактора переменных. К внутренним переменным нельзя подключать связи, они обычно используются для хранения параметров блока или для управления элементами его векторной картинки.
Входы могут получать данные через связи от других блоков (автоматически в режиме расчета или при вызове специальной сервисной функции в других режимах). Можно указать необходимость автоматического запуска модели блока в режиме расчета при срабатывании связи, подключенной к данному входу – для этого служит колонка «» редактора переменных. Например, в структуре переменных, изображенной на рис. 9, включен автоматический запуск модели при срабатывании связей, подключенных к переменным «x_in» и «y_in». Кроме того, к каждому входу блока можно привязать другую переменную сигнального типа: при срабатывании связи, подключенной к данному входу, в эту переменную автоматически запишется значение 1. Анализируя значения таких связанных сигналов, модель блока может выяснить, какие из связей, подключенных к блоку, сработали в предыдущем такте расчета. Поскольку в RDS нулевые значения сигнальных переменных не передаются при срабатывании связей, после анализа связанной сигнальной переменной модель блока должна самостоятельно сбросить эти сигналы в 0, чтобы получить возможность определить следующее срабатывание связи – иначе в переменной навсегда останется единичное значение, и модель не сможет отличить срабатывание следующей связи от предыдущей. Для привязывания сигнала к входу в редакторе переменных в колонке «» нужно выбрать для данной переменной вариант «Вход/Сигнал», и указать в этой же колонке имя связанного сигнала. На рис. 9 к входам «x_in» и «y_in» привязаны внутренние сигнальные переменные «x_in_ok» и «y_in_ok» соответственно. Подробнее использование связанных со входами сигналов рассматривается в §2.5.7.
К выходам блока могут подключаться связи, передающие данные на входы других блоков. С каждым выходом может быть связана дополнительная переменная логического типа – при этом связи, подключенные к этому выходу, сработают только в том случае, если эта переменная будет иметь значение 1 (истина). Для такой связи нужно в колонке «» редактора переменных выбрать вариант «Выход/Логическая» и указать имя связанной логической переменной. С выходами-массивами можно связать не только логическую переменную, управляющую передачей всего выхода в целом, но и целую – в этом случае будут работать только связи, присоединенные к элементу массива, номер которого определяется этой целой переменной, и связи, присоединенные ко всему массиву как к единому целому. Подробнее использование связанных со выходами управляющих переменных рассматривается в §2.5.8. Следует помнить, что в режиме расчета связи, присоединенные к выходам блока, срабатывают только в том случае, если вторая сигнальная переменная этого блока (выход «Ready») имеет единичное значение. При запуске модели блока в режиме расчета в эту переменную автоматически записывается единица, но блок может обнулить ее, чтобы блокировать передачу по связям значений всех своих выходов.
В колонке «» редактора переменных задается исходное значение переменной, которое она получит сразу после загрузки схемы, добавлении нового блока с этой структурой или после сброса расчета. Для массивов и матриц можно задать только исходный размер и значение по умолчанию для одного элемента, задать разные значения по умолчанию для разных элементов массива нельзя.
Рис. 10. Меню
подключения связи
Флаг в колонке редактора «» указывает на необходимость добавить имя данного входа или выхода в меню подключении связи (рис. 10). К входам и выходам без этого флага все равно можно подключить связь, но в меню их имена отображаться не будут, пользователь должен будет выбрать в нем пункт «» и указать имя подключаемой переменной в отдельном окне. Обычно флаг «» устанавливают для основных входов и выходов блока, а у дополнительных и редко используемых его сбрасывают, чтобы их имена не загромождали меню подключения связи.
Флаг в колонке «» управляет отображением имени входа или выхода на схеме по умолчанию: если он включен, при подключении новой связи к блоку рядом с точкой подключения будет выведено имя переменной, с которой соединена эта связь (см. имена переменных на рис. 1). Позже, независимо от состояния этого флага, изображение имени переменной можно включать и выключать по желанию – для этого предназначен отдельный пункт в контекстном меню точки связи.
Колонки «» и «» (с изображением двунаправленной стрелки), недоступные для изменения, показывают смещение к данной переменной от начала дерева и ее размер в байтах соответственно. Эти значения вычисляются автоматически, они могут пригодиться при написании модели блока для обращения к конкретной переменной при известном адресе начала дерева переменных в памяти. При написании функций моделей на языке C/C++ указатели на переменные не нужно вычислять вручную, для этого можно использовать макроопределения, генерируемые RDS.
Для однозначного определения типов всех переменных блока используется строка типа (см. рис. 9, внизу слева). В этой строке каждой переменной соответствует один или несколько символов, указывающих на тип этой переменной. Большинству типов соответствует один символ: сигнал – «S», логический – «L», char – «C», short – «H», int – «I», float – «F», double – «D», строка – «A», произвольный – «V». Массивам и матрицам соответствует символ «M», за которым следует тип элемента (например, «MD» – матрица переменных double, «MMA» – матрица матриц строк). Структурам соответствуют символы «{» и «}», между которыми указываются типы всех полей структуры (например, структура, состоящая из двух вещественных полей двойной точности, описывается строкой «{DD}»). На самом деле, весь набор переменных блока тоже является структурой, поэтому строка типа переменных блока всегда начинается с символа «{» и заканчивается символом «}». Например, тип переменных стандартного блока вычитания (имеющего, помимо двух обязательных сигналов «Start» и «Ready», два входа типа double и выход того же типа) описывается строкой «{SSDDD}» , где две буквы «S» соответствуют двум сигналам, а три буквы «D» – двум вещественным входам и выходу.
Модели блоков обычно используют строку типа для проверки, может ли данная модель работать с данной структурой статических переменных (чаще всего это делается в реакции на событие RDS_BFM_VARCHECK, см. §2.5.1). Эта проверка очень важна, так как модели обычно работают со статическими переменными по фиксированным смещениям относительно начала дерева переменных, и при несоответствии структуры переменных ожиданиям модели, в лучшем случае, будут считаны и записаны неверные значения, в худшем – возникнет ошибка общей защиты. Например, уже упомянутая стандартная модель блока вычитания откажется работать с любым блоком, строка типа переменных которого не «{SSDDD}». Эта модель обращается к переменным блока по следующим смещениям: 0 – первый сигнал («Start»), 1 – второй сигнал («Ready»), 2 (1+1) – первая вещественная («x1»), 10 (1+1+8) – вторая вещественная («x2»), 18 (1+1+8+8) – третья вещественная («y»). Если бы модель не проверяла типы переменных, при попытке подключить ее к блоку со строкой типа, например, «{SSD}», при обращении к переменной «y» (смещение 18) возникла бы ошибка общей защиты, поскольку байты 18-25 от начала области переменных находится за пределами отведенной памяти. В строке типа нигде не указывается, является ли переменная входом или выходом, она определяет только типы переменных и их последовательность в памяти. Если в структуре переменных блока вычитания поменять местами вход «x1» и выход «y», строка типов не изменится. Модель при этом будет работать неправильно, но, поскольку и переменная «x1», и переменная «y» имеют одинаковый размер и тип, фатальных ошибок, вроде ошибки общей защиты, не произойдет.