Промышленное производство
Промышленный Интернет вещей | Промышленные материалы | Техническое обслуживание и ремонт оборудования | Промышленное программирование |
home  MfgRobots >> Промышленное производство >  >> Industrial programming >> VHDL

Как создать управляемый Tcl тестовый стенд для модуля кодовой блокировки VHDL

Большинство симуляторов VHDL используют язык команд инструментов (Tcl) в качестве языка сценариев. Когда вы вводите команду в консоли симулятора, вы используете Tcl. Кроме того, вы можете создавать сценарии с помощью Tcl, которые запускаются в симуляторе и взаимодействуют с вашим кодом VHDL.

В этой статье мы создадим тестовый стенд с самопроверкой, который использует Tcl вместо VHDL, чтобы убедиться, что модуль VHDL ведет себя правильно.

См. также:
Зачем изучать Tcl
Интерактивный тестовый стенд с использованием Tcl

Вы можете загрузить код из этой статьи и проект ModelSim, используя форму ниже.

DUT:модуль кодового замка на VHDL

Прежде чем мы начнем на тестовом стенде, я представлю тестируемое устройство (ИУ). Это будет модуль кодового замка, который разблокирует хранилище, когда мы введем правильную последовательность цифр на клавиатуре с PIN-кодом.

Люди часто называют кодовый замок кодовым замком. . Однако я считаю этот термин неточным. Недостаточно ввести правильную комбинацию цифр, чтобы разблокировать его. Вы также должны ввести их в правильном порядке. Строго говоря, кодовый замок на самом деле является перестановочным замком. , но назовем это кодовым замком .

На изображении выше показан такой кодовый замок в виде гостиничного сейфа. Для простоты в нашем примере будут использоваться только цифровые клавиши, а не кнопки «ОЧИСТИТЬ» и «БЛОКИРОВАТЬ».

Как работает модуль кодового замка

Наш модуль запустится в запертом положении, и если мы введем подряд четыре цифры, совпадающие с секретным PIN-кодом, он разблокирует сейф. Чтобы снова заблокировать его, мы можем ввести другой, неправильный номер. Таким образом, нам нужно создать детектор последовательности в VHDL.

На графике выше показано, как будет работать модуль кодового замка. Помимо часов и сброса, есть два входных сигнала:input_digit и input_enable . Модуль должен произвести выборку входной цифры, когда разрешающая способность равна «1» на нарастающем фронте тактового сигнала.

Выход этого модуля только один:разблокировать сигнал. Представьте, что он управляет запирающим механизмом сейфа или хранилища. разблокировать сигнал должен быть только «1» только тогда, когда пользователь ввел четыре последовательных цифры, которые соответствуют правильному PIN-коду. В этой статье мы будем использовать код доступа 1234.

Объект

В приведенном ниже коде показана сущность модуля кодового замка. Поскольку целью этого модуля является простой пример тестируемого устройства для нашего тестового стенда на основе TCL, я жестко запрограммировал секретный код доступа с помощью дженериков. Четыре общие константы представляют собой двоично-десятичные числа (BCD), реализованные как целые числа с ограниченным диапазоном.

entity code_lock is
  generic (pin0, pin1, pin2, pin3 : integer range 0 to 9);
  port (
    clk : in std_logic;
    rst : in std_logic;
    input_digit : in integer range 0 to 9;
    input_enable : in std_logic;
    unlock : out std_logic
  );
end code_lock;

Как и пароль, input_digit сигнал также является двоично-десятичным типом. Другие входы и выходы — std_logics.

Декларативная область

Этот модуль имеет только один внутренний сигнал:регистр сдвига, который содержит четыре последние цифры, введенные пользователем. Но вместо того, чтобы использовать двоично-десятичный диапазон от 0 до 9, мы позволили числам изменяться от -1 до 9. Это 11 возможных значений.

type pins_type is array (0 to 3) of integer range -1 to 9;
signal pins : pins_type;

Мы должны использовать значение сброса, которое не является цифрой, которую пользователь может ввести, и для этого предназначен -1. Если бы мы использовали диапазон от 0 до 9 для пинов array, установка секретного кода доступа на 0000 изначально открыла бы хранилище. В этой схеме пользователю придется явно ввести четыре нуля.

Реализация

В верхней части области архитектуры я добавил параллельный оператор, который разблокирует хранилище, когда закрепляет signal соответствует общим константам. Приведенный ниже код является комбинационным, но поскольку булавки синхронизируется, разблокировка сигнал будет меняться только по переднему фронту тактового сигнала.

unlock <= '1' when pins = (pin3, pin2, pin1, pin0) else '0';

В приведенном ниже коде показан процесс, который считывает пользовательский ввод. Он создает сдвиговый регистр из контактов. сигнал, сдвигая все значения, когда input_enable равно «1» на нарастающем фронте тактового сигнала. В результате четыре последние введенные пользователем цифры сохраняются в пинах. массив.

PINS_PROC : process(clk)
begin
  if rising_edge(clk) then
    if rst = '1' then
      pins <= (others => -1);

    else

      if input_enable  = '1' then
        pins(0) <= input_digit;
        pins(1 to 3) <= pins(0 to 2);
      end if;

    end if;
  end if;
end process;

Тестовый стенд VHDL

Прежде всего, нам по-прежнему нужен базовый тестовый стенд VHDL, несмотря на то, что мы используем Tcl для проверки. В приведенном ниже коде показан полный файл VHDL. Я создал экземпляр DUT и создал тактовый сигнал, но это все. Помимо генерации часов, этот тестовый стенд ничего не делает.

library ieee;
use ieee.std_logic_1164.all;

entity code_lock_tb is
end code_lock_tb;

architecture sim of code_lock_tb is

  constant clk_hz : integer := 100e6;
  constant clock_period : time := 1 sec / clk_hz;

  signal clk : std_logic := '1';
  signal rst : std_logic := '1';
  signal input_digit : integer range 0 to 9;
  signal input_enable : std_logic := '0';
  signal unlock : std_logic;

begin

  clk <= not clk after clock_period;

  DUT : entity work.code_lock(rtl)
    generic map (1,2,3,4)
    port map (
      clk => clk,
      rst => rst,
      input_digit => input_digit,
      input_enable => input_enable,
      unlock => unlock
    );

end architecture;

Тестовый стенд Tcl

Код Tcl в этом примере работает только с симулятором ModelSim VHDL. Например, если вы хотите использовать его в Vivado, вам придется внести в него некоторые изменения. Это потому, что он использует несколько команд, специфичных для этого симулятора. Недостатком использования Tcl является то, что ваш код привязан к конкретному поставщику симулятора.

Для справки я рекомендую Tcl Developer Xchange, который охватывает язык Tcl в целом, и Справочное руководство по командам ModelSim, в котором описаны все специфичные для ModelSim команды.

Если у вас установлен ModelSim, вы можете загрузить пример проекта, используя форму ниже.

Использование пространства имен

Первое, что я рекомендую, это создать пространство имен Tcl. Это хорошая идея, потому что в противном случае вы можете непреднамеренно перезаписать глобальные переменные из вашего Tcl-скрипта. Помещая весь свой код в пространство имен, вы избегаете потенциального беспорядка. Мы будем помещать весь Tcl-код, который будем писать, внутрь codelocktb. пространство имен, как показано ниже.

namespace eval ::codelocktb {

  # Put all the Tcl code in here

}

Внутри пространства имен мы должны начать с моделирования, как показано ниже. Мы делаем это с помощью vsim команда, за которой следует имя библиотеки и объекта тестового стенда VHDL. Это загрузит симуляцию, но не запустит ее. Время симуляции не проходит, пока мы не используем run позже в сценарии. Мне также нравится включать оператор If, который загрузит сигнал, если он существует.

# Load the simulation
vsim work.code_lock_tb

# Load the waveform
if {[file exists wave.do]} {
  do wave.do
}

Объявление переменных пространства имен

Теперь, когда мы загрузили симуляцию, мы можем начать взаимодействовать с кодом VHDL. Во-первых, я хочу прочитать clock_period константа и общий пароль для среды Tcl.

В приведенном ниже коде я использую специфичный для ModelSim анализ команда для чтения сигнала VHDL и постоянных значений в Tcl. Затем я использую команды Tcl string и list для извлечения значения времени и единиц времени. пин-код переменная становится списком из четырех цифр, которые мы считываем из общих констант.

# Read the clock period constant from the VHDL TB
variable clockPeriod [examine clock_period]

# Strip the braces: "{10 ns}" => "10 ns"
variable clockPeriod [string trim $clockPeriod "{}"]

# Split the number and the time unit
variable timeUnits [lindex $clockPeriod 1]
variable clockPeriod [lindex $clockPeriod 0]

# Read the correct PIN from the VHDL generics
variable pinCode [examine dut.pin0 dut.pin1 dut.pin2 dut.pin3]

Обратите внимание, что я использую другой стиль кодирования в скрипте Tcl, чем в коде VHDL. Вместо подчеркивания я использую верблюжий регистр. Это потому, что я следую руководству по стилю Tcl. Конечно, ничто не мешает вам использовать один и тот же стиль в файлах Tcl и VHDL, если вы этого хотите.

Кроме того, если вы использовали Tcl без пространств имен, вы, вероятно, знаете о ключевом слове set, которое является стандартным способом определения переменной в Tcl. Здесь я использую ключевое слово newer variable вместо этого. Это похоже на глобальную переменную, привязанную к текущему пространству имен, а не к глобальной области.

Наконец, мы объявляем переменную с именем errorCount. и инициализируйте его значением 0, как показано ниже. По мере того, как симуляция проходит через тестовые примеры, мы будем увеличивать его каждый раз, когда обнаруживаем ошибку. В конце концов, мы можем использовать его, чтобы определить, прошел ли модуль или нет.

variable errorCount 0

Печать текста в ModelSim

Команда puts — это стандартный способ вывода текста на консоль в Tcl. Но этот метод плохо работает в ModelSim. Версия для Windows делает то, что вы ожидаете; он выводит строку на консоль. С другой стороны, в версии для Linux текст выводится в оболочке, из которой вы запустили ModelSim, а не в консоль в графическом интерфейсе.

На изображении ниже показано, что происходит, когда мы вводим puts. в консоли ModelSim. Он появляется в окне терминала сзади. Хуже того, если вы запустите ModelSim с помощью ярлыка на рабочем столе, вы никогда не увидите вывод, потому что оболочка скрыта.

Существуют обходные пути для изменения поведения путов. команда. Вы можете, например, переопределить его (да! Вы можете сделать это в Tcl) и заставить его работать на обеих платформах. Но более простым способом вывода текста на консоль как в Linux, так и в Windows является использование специфичного для ModelSim echo. команда.

Мы будем использовать пользовательскую процедуру Tcl, показанную ниже, для печати текста. При этом мы также добавляем к сообщению текущее время симуляции. В ModelSim вы всегда можете получить его с помощью $now глобальная переменная.

proc printMsg { msg } {
  global now
  variable timeUnits
  echo $now $timeUnits: $msg
}

Моделирование N тактов

ИУ является тактовым модулем, что означает, что между нарастающими фронтами тактового сигнала ничего не происходит. Поэтому мы хотим моделировать пошагово в зависимости от продолжительности тактового цикла. Процедура Tcl ниже использует clockPeriod и Единицы времени переменные, которые мы для этого извлекли из кода VHDL ранее.

proc runClockCycles { count } {
  variable clockPeriod
  variable timeUnits

  set t [expr {$clockPeriod * $count}]
  run $t $timeUnits
}

Процедура принимает один параметр:count. . Мы умножаем его на длину одного тактового периода, чтобы получить продолжительность N тактовых циклов. Наконец, мы используем ModelSim run команду для имитации именно столько времени.

Проверка значения сигнала из Tcl

В ModelSim мы можем прочитать сигнал VHDL из Tcl с помощью команды проверить команда. В приведенном ниже коде показана процедура Tcl, которую мы используем для чтения значения сигнала и проверки его соответствия ожиданиям. Если сигнал не соответствует expectedVal параметр, мы печатаем неприятное сообщение и увеличиваем errorCount переменная.

proc checkSignal { signalName expectedVal } {
  variable errorCount

  set val [examine $signalName]
  if {$val != $expectedVal} {
    printMsg "ERROR: $signalName=$val (expected=$expectedVal)"
    incr errorCount
  }
}

Проверка последовательности PIN-кода

Выход модуля кодового замка зависит не только от текущих входов, но и от их предыдущих значений. Следовательно, проверка выходов должна происходить как минимум после отправки четырех цифр на ИУ. Только после этого сигнал разблокировки должен измениться с «0» на «1», если PIN-код правильный.

Приведенная ниже процедура Tcl использует force ModelSim. ключевое слово для изменения сигналов VHDL из Tcl. -депозит переключиться на принудительно ключевое слово означает, что ModelSim изменит значение, но позволит другому VHDL-драйверу управлять им позже, хотя никакие другие объекты не контролируют входы DUT в нашем тестовом стенде.

proc tryPin { digits } {
  variable pinCode

  set pinStatus "incorrect"
  if { $digits == $pinCode } {
    set pinStatus "correct"
  }

  printMsg "Entering $pinStatus PIN code: $digits"

  foreach i $digits {
    force input_digit $i -deposit
    force input_enable 1 -deposit
    runClockCycles 1
    force input_enable 0 -deposit
    runClockCycles 1
  }

  if { $pinStatus == "correct" } {
    checkSignal unlock 1
  } else {
    checkSignal unlock 0
  }
}

tryPin процедура использует наш printMsg процедура, чтобы сообщить о том, что он делает, какой PIN-код он вводит, и является ли это правильным кодом доступа. Он также использует runClockCycles Процедура выполняется ровно один такт, манипулируя входами DUT, чтобы имитировать ввод PIN-кода пользователем.

Наконец, он использует checkSignal Процедура проверки того, что DUT ведет себя так, как ожидалось. Как я уже объяснял, checkSignal процедура напечатает сообщение об ошибке и увеличит errorCount переменная, если разблокировать сигнал не соответствует ожидаемому значению.

Тестовые случаи и статус завершения

В приведенном выше коде Tcl мы начали симуляцию и определили кучу переменных и процедур, но мы вообще не моделировали время. Симуляция по-прежнему находится на уровне 0 нс. Время моделирования не прошло.

Ближе к концу нашего пользовательского пространства имен мы начинаем вызывать процедуры Tcl. Как показано в приведенном ниже коде, мы начинаем с десяти тактов. После этого отпускаем сброс и проверяем, что разблокировка вывод имеет ожидаемое значение «0».

runClockCycles 10

# Release reset
force rst '0' -deposit
runClockCycles 1

# Check reset value
printMsg "Checking reset value"
checkSignal unlock 0

# Try a few corner cases
tryPin {0 0 0 0}
tryPin {9 9 9 9}
tryPin $pinCode
tryPin [lreverse $pinCode]

if { $errorCount == 0 } {
  printMsg "Test: OK"
} else {
  printMsg "Test: Failure ($errorCount errors)"
}

Мы могли бы попробовать все 10000 различных PIN-кодов, но это заняло бы значительное количество времени. Моделирование на основе Tcl намного медленнее, чем чистый тестовый стенд VHDL. Симулятору приходится много раз запускаться и останавливаться, а это занимает много времени. Поэтому я решил проверять только крайние случаи.

Мы вызываем tryPin четыре раза с PIN-кодами:0000, 9999, правильный PIN-код и цифры из правильного PIN-кода в обратном порядке. Я полагаю, что легко сделать ошибку при создании кодового замка, смотреть только на комбинацию, а не на порядок цифр.

Наконец, в самом конце кода Tcl, но все еще в пределах пространства имен, мы проверяем errorCount. переменную и вывести «Тест:OK» или «Тест не пройден».

Запуск тестового стенда

А теперь самое интересное:запуск тестового стенда. Я предпочитаю использовать исходную команду Tcl, как показано ниже, но вы также можете использовать специфичную для ModelSim команду do. команда. На самом деле файлы ModelSim DO — это просто файлы Tcl с другим суффиксом.

source code_lock/code_lock_tb.tcl

В финальной версии моего кода ошибок нет. В приведенном ниже листинге показан результат успешного моделирования. Сценарий Tcl информирует нас о том, что он делает, и мы видим, что все строки сообщений имеют отметку времени. Это наш printMsg процедура на работе. Наконец, тестовый стенд останавливается и печатает «Тест:ОК».

VSIM> source code_lock/code_lock_tb.tcl
# vsim 
...
# 110 ns: Checking reset value
# 110 ns: Entering incorrect PIN code: 0 0 0 0
# 190 ns: Entering incorrect PIN code: 9 9 9 9
# 270 ns: Entering correct PIN code: 1 2 3 4
# 350 ns: Entering incorrect PIN code: 4 3 2 1
# 430 ns: Test: OK

Однако я хочу показать вам, как это выглядит, когда тестируемое устройство не проходит тест. Для этого я создал ошибку в модуле кодового замка. Я заменил проверку pin1 с pin2 чтобы тестируемое устройство игнорировало pin1 ценность. Это легко сделать опечатку, как показано в коде ниже.

unlock <= '1' when pins = (pin3, pin2, pin2, pin0) else '0';

Теперь, когда мы запустим тестовый стенд, из приведенного ниже списка вы увидите, что ошибка обнаружена. И, наконец, тестовый стенд выводит «Тест:сбой» вместе с количеством ошибок.

VSIM> source code_lock/code_lock_tb.tcl
# vsim 
...
# 110 ns: Checking reset value
# 110 ns: Entering incorrect PIN code: 0 0 0 0
# 190 ns: Entering incorrect PIN code: 9 9 9 9
# 270 ns: Entering correct PIN code: 1 2 3 4
# 350 ns: ERROR: unlock=0 (expected=1)
# 350 ns: Entering incorrect PIN code: 4 3 2 1
# 430 ns: Test: Failure (1 errors)

Заключительные мысли

За свою карьеру я создал много тестовых стендов на основе Tcl, но мое мнение о них несколько разделилось.

С одной стороны, вы можете делать некоторые крутые вещи, которые невозможно сделать с помощью одного только VHDL. Например, интерактивный тестовый стенд. Также приятно, что вы можете изменить тестовый стенд без перекомпиляции. И, наконец, проверка с использованием совершенно другого языка может быть выгодной. Вам придется совершить одну и ту же ошибку в двух разных технологиях, чтобы она осталась незамеченной, а это маловероятно.

С другой стороны, есть и некоторые недостатки. Тестовые стенды на основе Tcl на порядок медленнее, чем их аналоги VHDL. Еще одна важная проблема — привязка к поставщику. Невозможно создать полностью переносимый тестовый стенд Tcl, в то время как тестовый стенд VHDL может работать на любом подходящем симуляторе.

И последняя причина, по которой тестовые стенды Tcl могут быть бесполезны, — это сам язык. В нем нет замечательных функций для предотвращения ошибок программирования, а отладка проблемы Tcl затруднена. Это не интуитивно понятный и не щадящий язык, как Python или Java.

Тем не менее, он служит связующим звеном между VHDL и миром программного обеспечения. А поскольку большинство инструментов FPGA, а не только симуляторы, поддерживают Tcl, я настоятельно рекомендую изучить его.

Эти мысли - всего лишь мое мнение. Расскажите мне, что вы думаете в разделе комментариев!


VHDL

  1. Как создать список строк в VHDL
  2. Как остановить симуляцию в тестовом стенде VHDL
  3. Как создать ШИМ-контроллер на VHDL
  4. Как создать кольцевой буфер FIFO в VHDL
  5. Интерактивный тестовый стенд с использованием Tcl
  6. Как создать самопроверяющийся тестовый стенд
  7. Как создать связанный список в VHDL
  8. Как использовать нечистую функцию в VHDL
  9. Как использовать функцию в VHDL
  10. Как бесплатно установить симулятор и редактор VHDL