Проектирование процессоров RISC-V в среде Logisim и на языке Verilog в среде Quartus

Основы работы в средах Logisim и Quartus Prime Lite

Разбить на страницы
Показывать лекцию целиком

Введение

Представленный Вашему вниманию курс "Проектирование процессоров RISC-V в среде Logisim и на языке Verilog в среде Quartus" представляет собой труд, направленный на последовательное освоение основ цифровой схемотехники результатом которого станет создание простого ядра процессора RISC-V.

При создании курса автор был нацелен обеспечить слушателей простым и доступным входом в освоение базовых основ цифрой электроники и открытой архитектуры RISC-V.

Теоретический материал дополняется обширной практической частью, в рамках которой изучаются ключевые блоки цифровых устройств: комбинационные и последовательностные схемы, регистры, счетчики, арифметико-логические устройства, модули памяти и дешифраторы.

Для освоения материала предлагается использование известной в академической среде программы моделирования устройств Logisim Evolution. Материал курса по данной среде является единственным открытым русскоязычным текстовым учебным пособием.

Помимо Logisim Evolution в курсе рассматриваются методы работы в среде Intel Quartus Prime, включая использование языка описания аппаратуры Verilog HDL для разработки цифровых модулей.

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

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

Получить основные навыки работы с графическими инструментами проектирования Logisim Evolution, а также навыки создания модулей на языке Verilog HDL в среде Quartus Prime.

Иметь представление об архитектуре современных процессоров и понимать принцип построения и функционирования процессоров RISC-V.

Презентация по установке инструментальных сред

Установка среды моделирования Logisim, среды разработки Quartus Prime Lite

Видеолекция. Основы Logisim (часть 1)

Видеолекция. Основы Logisim (часть 2)

Основы работы в средах Logisim и Quartus Prime Lite

Видеолекция. Описание работы в среде Quartus Prime Lite.

Краткий справочник по языку описания аппаратуры Verilog и основам верификации

Введение

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

Язык Verilog является одним из самых популярных языков описания аппаратуры (HDL), используемым для проектирования и моделирования работы цифровых и микропроцессорных систем. Удобство, выразительность, а также широкая поддержка языка со стороны инструментов проектирования, сделали Verilog неотъемлемой частью индустрии разработки цифровых устройств.

Verilog был разработан в 1984 году как язык описания аппаратуры, который позволяет проектировщикам описывать логику цифровых схем на высоком уровне абстракции. Он обеспечивает средства для описания как структурной, так и поведенческой модели аппаратуры. Структурное описание позволяет проектировать систему как комбинацию компонентов, тогда как поведенческое описание фокусируется на логике работы системы.

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

Язык Verilog обладает следующими преимуществами:

  • Объектно-ориентированный подход: Verilog поддерживает некоторые принципы объектно-ориентированного программирования, что упрощает организацию кода и его повторное использование. Инженеры могут создавать модули, которые могут быть и использованы в разных проектах, что увеличивает эффективность разработки. Создано большое количество открытых модулей, которые разработчики могут применять в своих проектах, что ускоряет процесс разработки.
  • Открытость и стандартизация: Язык стандартизован (IEEE 1364), что обеспечивает его совместимость и предсказуемость в использовании, а также стабильность инструментов, которые его поддерживают.
  • Поддержка тестирования: Verilog предоставляет мощные средства для проверки и тестирования проектируемых систем. Конструирование тестов и создание testbenches для верификации работы проектируемых схем -это неотъемлемая часть процесса проектирования. Так появился язык System Verilog, изначально разработанный для верификации, а в настоящее время применяемый для описания RTL.
  • Удобство для параллельного описания: Verilog позволяет описывать параллельно работающие процессы, что естественно отражает реальную архитектуру цифровых систем. Это делает язык особенно эффективным для описания сложных систем на кристалле (SoC), где множество компонентов работают одновременно.
  • Необходимо выделить ряд недостатков, которые по мере освоения языка начинающим разработчиком могут быть сняты:

  • Сложность синтаксиса: для начинающих разработчиков синтаксис Verilog может показаться сложным и запутанным, особенно при переходе от поведенческого описания к структурному.
  • Ограниченная выразительность: хотя язык позволяет представлять широкий спектр возможностей, но некоторые сложные конструкции могут быть неудобными для описания. Например, работа с состояниями и временными зависимостями может требовать значительных усилий.
  • 1. Вводные данные для описания аппаратуры на языке Verilog

    В целом необходимо выделить ряд существенных преимуществ языков описания аппаратуры над схемотехническим вводом:

  • Высокоуровневая абстракция. Verilog позволяет описывать функциональность устройства на более высоком уровне, чем схемотехнический ввод. Вместо начертания электрических схем можно формулировать свойства и поведение системы через код, что упрощает процесс проектирования и позволяет быстрее перейти от идеи к реализации. Verilog поддерживает описание как на уровне логических элементов (gate level), так и на уровне функциональных блоков (behavioral level). Это позволяет инженерам выбирать необходимый уровень детализации в зависимости от задачи.
  • Повторное использование кода. В Verilog модули могут быть определены один раз и использованы много раз, что сильно упрощает проектирование. Это позволяет создавать библиотеку заранее протестированных компонентов, что ускоряет процесс разработки.
  • Набор инструментов для верификации. Verilog позволяет создавать тестовые стенды (testbenches) для автоматической верификации проектируемых систем. Это позволяет обнаруживать ошибки и проводить тестирование на ранних этапах разработки без необходимости физической реализации схемы.
  • Легкость изменения и обновления. В случае необходимости изменения дизайна, изменения могут быть легко внесены в код. Это значительно экономит время по сравнению с обновлением схемы, где каждое изменение может потребовать полной переработки. Разработчики могут анализировать и отлаживать код, что гораздо удобнее и быстрее, чем изучение схем.
  • Упрощение процесса сопровождения и документации, а также читаемость. Код на Verilog может быть легче читаем и понятен другим инженерам, изучение схемы, что упрощает поддержку и сопровождение проектов. Документирование проекта на языках описания аппаратуры позволяет лучше структурировать и документировать проект, что делает его понятнее.
  • Интеграция с другими инструментами. Проект реализованный, например, Verilog легче переносить (интегрировать) в средах автоматизированного проектирования (CAD), что позволяет эффективно разрабатывать, моделировать и синтезировать сложные цифровые устройства.
  • Скорость реализации проекта.
  • В литературе можно встретить описание языков описания аппаратуры как составной системы из двух компонент: общеалгоритмической и проблемно-ориентированной.

    Алгоритмическая компонента языка Verilog заключается в схожести его семантики и синтаксиса с Си подобными языками. Язык содержит операторы, типы данных, процедурные блоки и функции.

    Проблемно-ориентированная компонента заключается в наличии интерфейсов, в том числе данных физического типа, сигналов, конкретизации применяемых компонентов.

    Освоение языка можно начать с формирования представления о зарезервированных словах.

    В языке Verilog определены следующие зарезервированные слова, применяемые при реализации описания схем - модулей. Соответственно для применения в качестве имен переменных, констант их использовать нельзя. Зарезервированные слова Verilog приведены в таблице 1.1.

    always

    and

    assign

    attribute

    automatic

    begin

    buf

    bufif0

    bufif1

    case

    casex

    casez

    cell

    cmos

    config

    deassign

    default

    defparam

    disable

    edge

    else

    end

    endattribute

    endcase

    endconfig

    endfunction realtime

    endgenerate

    endmodule

    endprimitive

    endspecify

    endtable

    endtask

    event

    for

    force

    forever

    fork

    function

    generate

    genvar

    highz0

    highz1

    if

    ifnone

    incdir

    include

    instance

    initial

    inout

    input

    integer

    join

    large

    liblist

    library

    localparam

    micromodule

    medium

    module

    nand

    negedge

    nmos

    nor

    not

    notif0

    notif1

    nowshowcancelled

    or

    output

    parameter

    pmos

    posedge

    primitive

    pull0

    pull1

    pulldown

    pullup

    pulsestyle_ondetect

    pulsestyle_onevent

    remos

    real

    reg

    release

    repeat

    rnmos

    rpmos

    rtran

    rtranif0

    rtranif1

    scalared

    signed

    small

    specify

    showcancelled

    specparam

    strength

    strong0

    strong1

    supply0 s

    upply1

    table

    task

    time

    tran

    tranif0

    tranif1

    tri

    tri0

    tri1

    triand

    trior

    trireg

    unsigned

    use

    vectored

    wait

    wand

    weak0

    weak1

    while

    wire

    wor

    xnor

    xor

    Необходимо закрепить базовые понятия, которыми необходимо руководствоваться при описании аппаратуры:

  • В Verilog имя (идентификатор) - последовательность букв и цифр, знаков "$" и "_", причем начинаться оно обязано не с цифры. Регистр имеет значение. Если начальный символ - "\", то следом за ним может идти любая последовательность символов. Все, что до пробела, будет считаться корректным именем. Например: "Namee", "nAmee", "$Char", "\c+Ha^ra".
  • При написании программного кода разработчик должен оставлять комментарии. В Verilog также существуют средства обозначения комментариев. Комментарии делятся на:

  • однострочные (//);
  • блочные (/* текст комментария или часть программы */).
  • Однострочными комментариями можно закомментировать часть одной строки или всю строку полностью.

  • Пунктуация - пробелы игнорируются. Точка с запятой используется для обозначения конца командной строки. Запятые, как правило, используются для отдельных элементов в списке.
  • Описание каждого объекта аппаратуры осуществляется в модулях и размещается между зарезервированными словами: module и endmodule.

    Создаваемые объекты должны иметь интерфейсы - порты.

    Порты в Verilog бывают трёх типов:

  • Input - вход;
  • Output - выход;
  • Inout - двунаправленный.
  • Порт объявляется следующим образом: тип [разрядность] имя порта;.

    Если не задана спецификация диапазона, например input [2:0] a, то считается, что порт имеет ширину одного бита, а передаваемые сигналы считаются скалярными. Если порт представляет собой шину, то есть имеет диапазон, то передаваемые сигналы считаются векторными.

    Порты могут иметь в объявлении константные выражения, через зарезервированное слова parameter. Также могут объявляться внутренние цепи через зарезервированное слово wire.

    Существует еще один тип источника сигнала reg. Данный тип при описании комбинационной логики ведет себя как переменная - провод wire. При проектировании синхронных схем сигнал reg способен сохранять значение, т.е. является триггером или регистром.

    Сигналы или переменные могут быть представлены следующими логическими уровнями:

  • 0: ноль, логический низкий уровень, "ложно", "земля" (zero, logic low, false, ground);
  • 1: единица, логический высокий уровень, "истина", "питание" (one, logic high, power);
  • X: неизвестное значение (unknown);
  • Z: высокий импеданс, неподключенный сигнал, третье состояние (high impedance, unconnected, tri-state).
  • Пример описания модуля приведен в листинге 1.1, где красным выделены зарезервированные слова, зеленым - пользовательские имена и коментарии, синим функционал.

    	module name_module 
    	#(parameter M=4) // константа
    (input [3:0] A,B, // четырехразрядные входы А и B 
    	input cin,// однопроводная линия
    	output  [M-1:0] S, //выход использующий для определения разрядности //константу 
    	output co); //выход линия
    	wire [4:0] sum; // внутренние сигналы
    assign sum = A + B + cin; // Суммируем A, B и cin 
    assign S = sum[M-1:0]; // Выход S - последние M разрядов суммы 
    assign co = sum[4]; // Выход переноса 
    endmodule
    

    1.1. Основы проектирования и верификации модулей

    Для начала решения проблемно-ориентированных задач, следует остановиться на важнейшем разделе любого проекта - определение этапов выполнения проекта:

  • Постановка задачи и формирование технического задания.
  • Формализация задания и выполнение математической модели.
  • Ввод описания проекта (выбор инструментов и способа описания, непосредственно описание проекта);
  • Построение моделирующего алгоритма
  • Создание тестового окружения и верификация проекта.
  • Отладка и устранение выявленных ошибок, выполнение повторных тестов.
  • Анализ результатов и их документирование.
  • Передача результатов заказчику.
  • Сформируем следующую задачу: необходимо разработать и реализовать схему с тремя входами для мажоритарного контроля, используя язык описания аппаратуры Verilog. Схема должна сравнивать три входа и выдавать сигнал, равный лог. "1" если два или более входов равны лог. "1".

    Уточним требования к интерфейсу проектируемой схемы и уровням сигналов реакции:

  • Входные сигналы:

  • a: первый вход (сигнал 1 бит);
  • b: второй вход (сигнал 1 бит);
  • c: третий вход (сигнал 1 бит);
  • Выходной сигнал - y, на котором установится лог. "1" если как минимум на двух входах будет присутствовать лог "1".
  • Выполним математическое моделирование. Для этого сформируем по условиям таблицу истинности (таблица 1.2).

    п/п Входы Выход
    A b c y
    1 0 0 0 0
    2 0 0 1 0
    3 0 1 0 0
    4 0 1 1 1
    5 1 0 0 0
    6 1 0 1 1
    7 1 1 0 1
    8 1 1 1 1

    Проведем анализ таблицы 1.2 истинности и определим строки, в которых комбинация входных сигналов обеспечит лог. "1" на выходе. В данном случае это 4, 6,7,8 строки. Выпишем их:

  • (a=1,b=1,c=0);
  • (a=1,b=0,c=1);
  • (a=0,b=1,c=1);
  • (a=1,b=1,c=1);
  • Сформируем СКНФ из данных:

    $$y=a*b*\bar c+a*\bar b*c+]bar a*b*c+a*b*c$$

    После преобразований формула примет вид:

    $$y=(a*b)+(b*c)+(a*c)$$

    Введем проект на заявленном языке Verilog. Определим имя модуля как major, тип сигнала интерфейса - wire. Имена сигналов были заданы в условии.

    Используя процедурный оператор assign, введем функцию, описанную выше на языке Verilog как показано в листинге 1.2.

    module major ( // начало модуля
        input wire a, // первый вход
        input wire b, // второй вход
        input wire c, // третий вход
        output wire y // выход мажоритарного значения
    );
    assign y = (a  b) | (b  c) | (c  a); // реализуемая функция
    endmodule // окончание модуля
    

    1.1.1. Верификация

    При создании цифровых устройств одним из сложных и самых трудоемких этапов является процесс верификации. Данный этап может отвлекать от 50 до 80% всего времени выполнения проекта.

    Верификация - это процесс установления соответствия созданного устройства, техническим условиям спецификации из технического задания.

    В рамках верификации выполняются различные тесты, причем могут вноситься изменения в конечную спецификацию устройства.

    В рамках выполнения верификации одним из этапов является процедура функциональной верификации - проверка на наличие ошибок в проекте. Для выполнения функциональной верификации применим инструменты симуляции работы схемы.

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

    Для проверки разработанного кода перенесем его в среду проектирования Intel Quartus.

  • Создадим проект с именем major.
  • Создадим новый файл Verilog HDL и введем код из листинга, сохраним файл с именем major.v.
  • Выполним компиляцию проекта в основном меню среды "Processing" - "Start Compilation"
  • Далее воспользуемся инструментом для ввода тестовых векторов, отслеживания изменения внутренних линий и состояния выходных портов - Waveform Editor. Для этого пройдя в меню "File" - "New", выберем в разделе "Verification/Debugging Files" пункт "University Program VWF".
  • В открывшейся форме (рисунок 1.1), добавим входы и выход модуля через меню "Edit" - "Insert" - "Insert Node or Bus" (рисунок 1.2). Нажав на кнопку "Node Finder", перейдем на форму выбора сигналов. Так как мы выбираем все сигналы, нажмем на кнопку "List". Исследуемые сигналы (все) переместим в поле "Selected Nodes", нажав на кнопку >> (рисунок 1.3).

    (рис 1.1) (рис 1.2) (рис 1.3)
  • Необходимо исключить один из параметров работы симулятора - noopt. Для этого перейти в меню "Simulation" - "Simulation Settings".

    В открывшемся окне, найдем данный параметр и удалим (рисунок 1.4).

    (рис 1.4)
  • Далее выполняется создание тестовых уровней сигналов. Для этого левой кнопкой мыши выбирается временной отрезок (одна или несколько клеток). После выбора он заливается синим цветом. Далее необходимо в меню инструментов выбрать уровень сигнала, в данном случае выбрать лог. "1" -.
  • Исходя из таблицы истинности формируем тестовые сигналы как показано на рисунке 1.5.
  • Далее выполняется функциональная симуляция через меню "Simulation" - "Run Functional Simulation". Полученную диаграмму (рисунок 1.6) необходимо сверить с заданными в техническом задании условиями, а также с таблицей истинности.
  • (рис 1.5) (рис 1.6)

    Более совершенные методы верификации подразумевают применение тестирующего оборудования или отладочного модуля, именуемого testbench. Testbench генерирует набор сигналов для проектируемого устройства, а затем принимает их для последующего анализа.

    Стратегия работы с тестовым окружением - поочередная подача восьми возможных комбинаций на входы a,b,c

    Для создания testbench необходимо рассмотреть основы синтаксиса данных файлов.

    Первая строка кода testbench может содержать директиву масштаба модельного времени, определяющая значение залежек модели, которая начинается с обратной кавычки: `timescale. С этой директивой указываются временные параметры: N1 - определяет единицы времени задержки сигналов, следующих за символом #; N2 - точность расчета.

    Оба параметра указываются в наносекундах или пикосекундах и могут принимать значения только 1, 10 или 100. По умолчанию назначаются ps.

    Пример: `timescale 1ns/1ns

    В следующей строке тестового модуля указывается ключевое слово module и имя модуля с обязательной приставкой tb, указывающей на то, что это тестовый модуль проекта.

    Так как это тестовый модуль, то он не имеет портов. В него вставляется тестируемый модуль и входы/ выходы тестируемого модуля взаимодействуют с переменными типа reg и wire.

    Например, для тестируемого модуля будет применено следующее объявление:

    reg a;
    reg b;
    reg c;
    wire y;
    

    Следующей частью кода является инстанцирование тестируемого модуля в тестовый модуль. При этом в списке портов устанавливается соответствие между портами тестового и тестируемого модулей. Модуль testbench в общем случае, может иметь отличные от тестируемого имена входов/выходов.

    После имени тестируемого модуля должен быть указан тип подсистемы, которая тестируется:

  • DUT (device under test), обозначает любое устройство или компонент, который тестируется. Это может быть целая система или отдельный модуль, в зависимости от уровня верификации.
  • UUT (unit under test), это подмножество DUT, обычно подчеркивающее конкретный модуль или блок, который тестируется в рамках более крупного устройства или системы.
  • Пример инстанцирования для рассматриваемого примера:

    major uut (
        .a(a),
        .b(b),
        .c(c)
    

    Далее с помощью конструкций, определяемых ключевыми словами initial begin…end выполняется моделирование.

    Конструкции содержат описания начальных значений и дальнейшего поведения входных сигналов во времени. Блок initial задает симулятору точку, с которой начинается работа. Следует отметить, что тестовый модуль без блока initial не работает.

    Следующим этапом указываются варианты поведения сигналов и указание временных единиц (задержки) для их смены.

    Также можно применять команды для вывода информации во время симуляции:

  • $display, выводит информацию только в момент вызова;
  • $monitor, выводит информацию каждый раз при изменении отслеживаемых переменных.
  • Пример: $monitor("a=%b, b=%b, c=%b, y=%b", $time, a, b, c, y);

    Далее указывается одна из конструкций системной директивы $finish, которая завершает процесс моделирования. И наконец, ключевое слово endmodule указывает на окончание описания тестового модуля.

    В листинге 1.3 приведен исходный код тестового модуля tb_major

    `timescale 1ns/1ns
    module tb_major;
    reg a;
    reg b;
    reg c;
    wire y;
    major uut (
        .a(a),
        .b(b),
        .c(c),
        .y(y)
    );
    
    initial begin
        
        $monitor("a=%b, b=%b, c=%b, y=%b", $time, a, b, c, y);
        
        a = 0; b = 0; c = 0;//y=0  
        #10; 
        a = 0; b = 0; c = 1;//y=0  
        #10; 
        a = 0; b = 1; c = 0;//y=0 
        #10; 
        a = 0; b = 1; c = 1;//y=1 
        #10; 
        a = 1; b = 0; c = 0;//y=0 
        #10; 
        a = 1; b = 0; c = 1;//y=1
        #10; 
        a = 1; b = 1; c = 0;//y=1
        #10; 
        a = 1; b = 1; c = 1;//y=1
        #10; 
          $finish;
    end
    endmodule
    

    Для реализации верификации с использованием созданного тестового модуля необходимо выполнить ряд манипуляций с проектом.

  • Файл testbench сохранить в каталоге проекта под именем tb_major.v;
  • Перейти в меню "Tools" - "Options". В открывшемся окне, перейти на вкладку EDA Tool Options (рисунок 1.7). В поле Modelsim-Altera указать путь к каталогу симулятора (по умолчанию: C:\intelFPGA_lite\20.1\modelsim_ase\win32aloem). Нажать кнопку ОК.
  • Перейти в меню "Assigments" - "Settings". В открывшемся окне, перейти в раздел "EDA Tool Settings". В строке "Simulation" для столбца "Tool Name" выбрать Modelsim-Altera. В столбце "Format(s) " выбрать Verilog HDL (рисунок 1.8). Нажать кнопки Apply и OK.

    (рис 1.7) (рис 1.8)
  • Далее в меню пройти в меню "Assigments" - "Settings". В открывшемся окне, перейти в подраздел "Simulation" раздела "EDA Tool Settings". В окне настроек установить метку "Compile test bench" (рисунок 1.9).

    (рис 1.9)
  • Нажать кнопку Test Benches. В новом окне (рисунок 1.10), нажать накнопку New.

    (рис 1.10)
  • В диалоговом окне, приведенном на рисунке 1.11, в поле Test bench name ввести tb_major. Далее добавить файл, нажав на кнопку "… " поля "File name". Выбрать файл и нажать кнопку Add, затем кнопку ОК.

    (рис 1.11)
  • Вернувшись в окно Test Benches, убедиться, что файл добавлен (рисунок 1.12). Далее нажать OK.

    (рис 1.12)
  • В окне "Settings" нажать кнопки Apply и OK.
  • Выполнить компиляцию проекта. В случае успешной компиляции запустить симуляцию проекта ("Tools" - "Run Simulation Tool" - "RTL Simulation"). Откроется инструмент ModelSim.
  • Результат симуляции отобразится в виде диаграммы на панели Wave (рисунок 1.13). Текстовые сообщения выводятся в панели Transcript.
  • Убедившись в верности отображаемых данных, можно окончить работу симуляции и завершить работу программы ModelSim.
  • (рис 1.13)

    Необходимо отметить, что качественный testbench должен содержать код самопроверки, то есть операторы, отслеживающие возникновение ошибки в ходе работы.

    2. Представление целых и действительных чисел в Verilog

    Для представления целых чисел применяется следующий формат записи: size'base value, где size - размер, определяющий систему счисления, в которой представлено число, base - система счисления числа, value - непосредственное значение.

    Для обозначения базы применяются следующие символы:

  • 'd или 'D - десятичные числа;
  • 'b или 'B - двоичные числа;
  • 'o или 'O - восьмеричные числа;
  • 'h или 'H - шестнадцатеричные числа;
  • Примеры:

    4'b1010 - двоичное четырёхразрядное число (в десятичной системе 10);

    6'o71 - шестиразрядное восьмеричное число;

    8'd127 - восьмиразрядное десятичное число 127;

    127 - десятичное число (по умолчанию).

    Для представления действительных чисел в Verilog применяется запись либо c десятичной точкой, либо в экспоненциальном виде. Запись с точкой имеет вид: value_i.value_f, где: value_i - целая часть, value_f - дробная часть

    Примеры:

    1.8
    3.8e10 // e или E для равно $$3,8*10^{10}$$
    2.1e-9// 2,1*$$10^{-9}$$
    

    3. Выражения

    Выражения и операции на языке Verilog, применяющие примитивы относятся к следующим видам:

  • логические операции, например, a b - логическое "И";
  • арифметические операции, например, a + b - это сложение двух чисел одинаковой разрядности с переполнением;
  • побитные операции, например, a b - это побитное "И" двух битовых массивов одинаковой длины;
  • отношения, например, a<b возвращает логическую 1, если число, двоичная запись которого есть a, меньше такового для b, и логический 0 иначе.
  • конкатенации, например, {a, b} - битовый массив, составленный из a и b;
  • редукции, например, a - имеет логическую 1, если все биты a равны лог "1", и логический 0 иначе;
  • условия,например, cond ? a : b работает как в C++. cond должно иметь логическое значение, a и b должны иметь одинаковое число бит.
  • В таблице 1.3 приведены операции языка Verilog для построения выражений.

    Побитные операторы
    ~ инверсия
    побитное "И"
    | побитное "ИЛИ"
    ^ побитное "Исключающее ИЛИ"
    ~^ или ^~ побитное "Исключающее ИЛИ НЕ"
    Логические операторы
    ! логическое "НЕ"
    AND логическое "И"
    || OR логическое "ИЛИ"
    Редукция
    редуцированное "И"
    ~ редуцированное "НЕ-И"
    | редуцированное "ИЛИ"
    ~| редуцированное "НЕ-ИЛИ"
    ^ редуцированное "Исключающее ИЛИ"
    ~^ или ^~ редуцированное "Исключающее ИЛИ НЕ"
    Арифметические операторы
    + сложение
    - вычитание
    * умножение
    / деление
    Отношение
    > больше
    < меньше
    >= больше либо равно
    <= меньше либо равно
    = = логическое равенство
    != логическое неравно
    = = = 4 state логическое равенство
    != = 4 state логическое неравно
    Операции сдвига
    >> логический сдвиг вправо
    << логический сдвиг влево
    >>> арифметический сдвиг вправо
    <<< арифметический сдвиг влево
    Разное
    { , } склеивание
    {n{m}} копирует m значение n раз
    ? : условие

    В листинге 1.3 приведен пример организации комбинационной схемы сравнения, использующей операторы отношения.

    module comparator (
    input [7:0] A, B,
    output O_EQ, O_NE, O_BR, O_MR, O_BOL, O_MEN);
    assign O_EQ = A == B;
    assign O_NE = A != B;
    assign O_BR = A >= B;
    assign O_MR = A <= B;
    assign O_BOL = A >B;
    assign O_MEN = A < B;
    endmodule
    

    4. Оператор непрерывного присваивания assign

    Оператор assign в Verilog предназначен для описания непрерывных присвоений в структуре цифровых схем. Этот оператор используется для связывания значений между сигналами и переменными.

    Назначение оператора assign:

  • Позволяет задавать непрерывные присвоения между проводами и переменными. Это означает, что результат выражения всегда будет обновляться автоматически при изменении входных сигналов.
  • С помощью assign можно описываются логические цепи и комбинационные схемы.
  • В листинге 1.4 дается пример применения оператора assign. На рисунке 1.14 можно наблюдать результат на уровне RTL.

    module logic_operators
    ( input [3:0] a, b, // объявление входных векторных портов 
    output [3:0] y, // объявление выходного векторного порта 
    output z); 
    assign y = a  b; // побитная операция " И" над входами
    assign z =  y; // редукция, объединение выходов y через операцию "И" и получение выхода //Z
    endmodule
    
    (рис 1.14)

    Возможно присваивание при объявлении, например, wire [2:0] z = x + y;.

    5. Процедурные блоки initial и always

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

    В симуляциях блоки initial выполняются только один раз в момент старта симуляции. Это делает их идеальными для настройки начальных значений переменных и запуск тестов.

    Блок always в Verilog предназначен для описания синхронных и асинхронных схем, а также для сложных комбинационных схем. Он используется для определения логики управления, где состояние выходных сигналов зависит от состояния входных сигналов.

    Пример: always @ (posedge clock) . Приведенный код позволяет запускать логику только по фронту тактового сигнала.

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

    В асинхронных схемах always применяется для описания поведения схем, которые реагируют на изменения входных сигналов немедленно, без учета тактового сигнала.

    Общий вид записи: блока always @(<сигналы>) <действия>, где <сигналы> - это список всех входных сигналов, к которым чувствителен блок. Это список входных сигналов, изменение которых влияет на выходные сигналы этого блока. Выполнение оператора или операторов в блоке <действия> будет приостановлено, до тех пор, пока не произойдет изменение какого-либо из сигналов в списке чувствительности.

    В списке чувствительности имена входных сигналов разделяются ключевым словом "or" , например, always @(a or b or d) <statements>.

    Иногда гораздо проще и надежней включать в список чувствительности все сигналы. Это делается аналогично примеру: always @* <statements>.

    Для присвоения значения сигналам в процедурных блоках initial и always применяются типы данных из класса переменных reg.

    Как было отмечено выше reg - переменная, занимающая в памяти определенное число битов (диапазон *… : …+), по умолчанию - 1 бит.

    Примеры объявления переменных:

    reg a, b, c ; // три скалярные однобитовые переменные

    reg signed [7:0] d1, d2; // две 8-битовые переменные со знаком

    reg [7:0] Q[0:3][0:15] ; // двумерный массив 8-битовых переменных

    reg clock = 0, reset=1; // две переменные типа reg с начальными значениями.

    При использовании конструкции always для комбинационных и асинхронных последовательностных схем применяется оператор блокирующего присваивания (=). Операторы выполняются один за другим. Пример:

    always @(*) //анализируем все сигналы
    begin
    	y=ab;
    	z= a||b;
    end
    

    Для проектирования последовательностной синхронной логики в блоке always применяется неблокирующее присваивание (<=). В данном случае список чувствительности содержит сигналы от значения которых зависит, когда произойдет сохранение значения переменной.

    Пример:

    wire d, clk;
    reg q;
    	always @ (posedge clk)
    	q<=d;
    

    Пример неблокирующего присваивания для получения последовательного регистра приведен в листинге 1.5.

    module nonb_trigger (
    input d,clk,
    output reg q,q1,q2,q3);
    always @(posedge clk)
    begin
    	q<=d;
    	q1<=q;
    	q2<=q1;
    	q3<=q2;
    end
    endmodule
    

    Из описания модуля в листинге видно, что значения всех переменных формируются по фронту clk. Первый оператор присваивает переменной q значение с входа d, но при этом другие присваивания не блокируются. Так как значение d еще неизвестно, а оно будет известно только в следующем такте фронта clk, поэтому следует что значение на входе q1 изменится на следующем такте.

    RTL представление модуля представлено на рисунке 1.15.

    (рис 1.15)

    Для описания условий в Verilog применяются условия стандартные для высокоуровневых языков программирования. Пример приведен в листинге 1.4.

    Общий вид записи:

     if(<условие>)
     	<действие1>; 
    else 
    <действие 2>;
    

    Пример, описывающий применение данной конструкции, показан для D-триггера в листинге 1.6. Если на вход rst поступает лог. "0", триггер сбрасывается. В противном случае происходит неблокирующее присваивание переменной q данных с входа d по фронту сигнала clk.

    always @(posedge clk or negedge rst_n) // Анализируем два сигнала
    begin 
    if (!rst_n) // если вход rst_n переходит в 0 - спад 
    q <= 1'b0; // сбрасываем выход 
     else 
    q <= d; // иначе на выход поступают данные или с переменной d
    end
    

    Также в Verilog возможно применение конструкции else if, то есть проверка работы предыдущего условия. Если оно не исполнено, то осуществляется обработка условия в конструкции eslse-if, последующие конструкции не обрабатываются.

    В листинге 1.7 приведен код для реализации двухразрядного дешифратора с применением конструкции eslse-if. На рисунке 1.16 приведено RTL представление модуля дешифратора.

      module shifr (
        input [1:0] in,     // вход (2 разряда)
        output reg [3:0] out // выход (4 разряда)
    );
    // проверка изменения сигналов на входе
    always @(*) begin
        // сброс выхода
        out = 4'b0000; 
        // Дешифрация входного кода
        if (in == 2'b00) 
            out = 4'b0001; // активен выход 0
         else if (in == 2'b01) 
            out = 4'b0010; // активен выход 1
         else if (in == 2'b10) 
            out = 4'b0100; // активен выход 2
         else if (in == 2'b11) 
            out = 4'b1000; // активен выход 3
    		else out=4'bxxxx;
        end
    endmodule
    
    (рис 1.16)

    Использование оператора if вводит большие задержки, потому что подразумевает вычисление выражения для сигналов (при моделировании работы схемы) в том порядке, в котором они появляются в модели (выражение в конечной ветви оператора if вычисляется последним).

    Правильным и более выразительным вариантом проверки входных условий может быть метод case, который позволяет сделать выбор из многих вариантов (на языке схемотехники мультиплексор со многими входами).

    Конструкция case схожа по синтаксису и формату применения с высокоуровневыми языками программирования.

    Базовый синтаксис следующий:

    case (<проверяемый операнд>)
      option1: <действие>;
      option2: <действие >;
      default:  <если не работают условия выше>;   
    endcase
    

    В разделе "Комбинационные схемы" данного курса данная конструкция применяется при описании дешифратора семисегментного индикатора.

    В листинге 1.8 приведен пример работы с case для описанного выше двухразрядного дешифратора.

    module shifr1 (
        input [1:0] in,       //вход (2 разряда)
        output reg [3:0] out  // выход (4 разряда)
    );
    
    // проверка изменения сигналов на входе
    always @(*) begin
        // сброс выходов
        out = 4'b0000; 
        
        // Дешифрация входного кода
        case (in)
            2'b00: out = 4'b0001; // активен выход 0
            2'b01: out = 4'b0010; // активен выход 1
            2'b10: out = 4'b0100; // активен выход 2
            2'b11: out = 4'b1000; // активен выход 3
            default: out = 4'b0000; // по умолчанию сброшен
        endcase
    end
    
    endmodule
    

    На рисунке 1.17 приведена RTL схема данного модуля. Как видно из рисунка схема получила вид дешифратора.

    (рис 1.17)

    6. Функции в языке Verilog

    Для сокращения кода описываемого узла или устройства можно сводить повторяющиеся блоки в функции. Синтаксис функций схож с языком С.

    Базовый синтаксис следующий:

    Function [<возвращаемый тип>] <имя> ([список портов])
     <действия> 
    Endfunction
    

    В листинге 1.9 приведен пример функции, реализующей 8-разрядный сумматора.

    function [7:0] sum (input [7:0] a,b);// объявление функции портов и выходного тип данных и //аргумента
    begin 
    sum=a+b;// реализуемая функция 
    end 
    endfunction
    

    На данном этапе обзор языка Verilog и его основных конструкций закончен.

    С объемными материалами по разработке на FPGA с использованием Verilog можно ознакомиться:

  • на курсе "Введение в FPGA и Verilog". (НИУ МФТИ).
  • В рамках "Школы синтеза цифровых схем"
  • Также рекомендуется изучение и применение дополнительной литературы и информационных источников:

  • Соловьев В.В. Язык Verilog в проектировании встраиваемых систем на FPGA. - М.: Горячая линия - Телеком, 2022. - 440с.: ил.
  • Акчурин А.Д., Юсупов К.М. Программирование на языке Verilog [Электронный ресурс] (Дата обращения 08.08.2024)
  • Филиал МИРЭА в г. Фрязино Методические рекомендации для проведения лабораторных занятий по курсу "Цифровые системы" МЕ2200 [Электронный ресурс] (Дата обращения 15.07.2024)
  • Сайт marsohod.org [Электронный ресурс] (Дата обращения 12.07.2024)
  • Дополнительная литература

    по среде Logisim

  • Скаков П.С., Яковлева В.Е. Архитектура ЭВМ: учебно-методическое пособие по лабораторным работам. - Санкт-Петербург: Университет ИТМО, 2023. - 99 с. - экз. [Электронный ресурс] (Дата обращения 15.09.2024)
  • Попов Д.И., Лилов И.П. "Организация ЭВМ. Лабораторные работы в программе Logisim" Москва, 2011 [Электронный ресурс] (Дата обращения 15.09.2024)
  • George Self Logisim Lab manual [Электронный ресурс] (Дата обращения 31.07.2024)
  • По языку Verilog HDL и среде Intel Quartus Prime Lite Edition

  • Соловьев В.В. Язык Verilog в проектировании встраиваемых систем на FPGA. - М.: Горячая линия - Телеком, 2022. - 440с.: ил.
  • Акчурин А.Д., Юсупов К.М. Программирование на языке Verilog [Электронный ресурс] (Дата обращения 08.08.2024)
  • Филиал МИРЭА в г. Фрязино Методические рекомендации для проведения лабораторных занятий по курсу "Цифровые системы" МЕ2200 [Электронный ресурс] (Дата обращения 15.07.2024)
  • Сайт marsohod.org [Электронный ресурс] (Дата обращения 12.07.2024)
  • Страницы:

    Введение

    Представленный Вашему вниманию курс "Проектирование процессоров RISC-V в среде Logisim и на языке Verilog в среде Quartus" представляет собой труд, направленный на последовательное освоение основ цифровой схемотехники результатом которого станет создание простого ядра процессора RISC-V.

    При создании курса автор был нацелен обеспечить слушателей простым и доступным входом в освоение базовых основ цифрой электроники и открытой архитектуры RISC-V.

    Теоретический материал дополняется обширной практической частью, в рамках которой изучаются ключевые блоки цифровых устройств: комбинационные и последовательностные схемы, регистры, счетчики, арифметико-логические устройства, модули памяти и дешифраторы.

    Для освоения материала предлагается использование известной в академической среде программы моделирования устройств Logisim Evolution. Материал курса по данной среде является единственным открытым русскоязычным текстовым учебным пособием.

    Помимо Logisim Evolution в курсе рассматриваются методы работы в среде Intel Quartus Prime, включая использование языка описания аппаратуры Verilog HDL для разработки цифровых модулей.

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

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

    Получить основные навыки работы с графическими инструментами проектирования Logisim Evolution, а также навыки создания модулей на языке Verilog HDL в среде Quartus Prime.

    Иметь представление об архитектуре современных процессоров и понимать принцип построения и функционирования процессоров RISC-V.

    Презентация по установке инструментальных сред

    Установка среды моделирования Logisim, среды разработки Quartus Prime Lite

    Видеолекция. Основы Logisim (часть 1)

    Видеолекция. Основы Logisim (часть 2)

    Основы работы в средах Logisim и Quartus Prime Lite

    Видеолекция. Описание работы в среде Quartus Prime Lite.

    Краткий справочник по языку описания аппаратуры Verilog и основам верификации

    Введение

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

    Язык Verilog является одним из самых популярных языков описания аппаратуры (HDL), используемым для проектирования и моделирования работы цифровых и микропроцессорных систем. Удобство, выразительность, а также широкая поддержка языка со стороны инструментов проектирования, сделали Verilog неотъемлемой частью индустрии разработки цифровых устройств.

    Verilog был разработан в 1984 году как язык описания аппаратуры, который позволяет проектировщикам описывать логику цифровых схем на высоком уровне абстракции. Он обеспечивает средства для описания как структурной, так и поведенческой модели аппаратуры. Структурное описание позволяет проектировать систему как комбинацию компонентов, тогда как поведенческое описание фокусируется на логике работы системы.

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

    Язык Verilog обладает следующими преимуществами:

  • Объектно-ориентированный подход: Verilog поддерживает некоторые принципы объектно-ориентированного программирования, что упрощает организацию кода и его повторное использование. Инженеры могут создавать модули, которые могут быть и использованы в разных проектах, что увеличивает эффективность разработки. Создано большое количество открытых модулей, которые разработчики могут применять в своих проектах, что ускоряет процесс разработки.
  • Открытость и стандартизация: Язык стандартизован (IEEE 1364), что обеспечивает его совместимость и предсказуемость в использовании, а также стабильность инструментов, которые его поддерживают.
  • Поддержка тестирования: Verilog предоставляет мощные средства для проверки и тестирования проектируемых систем. Конструирование тестов и создание testbenches для верификации работы проектируемых схем -это неотъемлемая часть процесса проектирования. Так появился язык System Verilog, изначально разработанный для верификации, а в настоящее время применяемый для описания RTL.
  • Удобство для параллельного описания: Verilog позволяет описывать параллельно работающие процессы, что естественно отражает реальную архитектуру цифровых систем. Это делает язык особенно эффективным для описания сложных систем на кристалле (SoC), где множество компонентов работают одновременно.
  • Необходимо выделить ряд недостатков, которые по мере освоения языка начинающим разработчиком могут быть сняты:

  • Сложность синтаксиса: для начинающих разработчиков синтаксис Verilog может показаться сложным и запутанным, особенно при переходе от поведенческого описания к структурному.
  • Ограниченная выразительность: хотя язык позволяет представлять широкий спектр возможностей, но некоторые сложные конструкции могут быть неудобными для описания. Например, работа с состояниями и временными зависимостями может требовать значительных усилий.
  • 1. Вводные данные для описания аппаратуры на языке Verilog

    В целом необходимо выделить ряд существенных преимуществ языков описания аппаратуры над схемотехническим вводом:

  • Высокоуровневая абстракция. Verilog позволяет описывать функциональность устройства на более высоком уровне, чем схемотехнический ввод. Вместо начертания электрических схем можно формулировать свойства и поведение системы через код, что упрощает процесс проектирования и позволяет быстрее перейти от идеи к реализации. Verilog поддерживает описание как на уровне логических элементов (gate level), так и на уровне функциональных блоков (behavioral level). Это позволяет инженерам выбирать необходимый уровень детализации в зависимости от задачи.
  • Повторное использование кода. В Verilog модули могут быть определены один раз и использованы много раз, что сильно упрощает проектирование. Это позволяет создавать библиотеку заранее протестированных компонентов, что ускоряет процесс разработки.
  • Набор инструментов для верификации. Verilog позволяет создавать тестовые стенды (testbenches) для автоматической верификации проектируемых систем. Это позволяет обнаруживать ошибки и проводить тестирование на ранних этапах разработки без необходимости физической реализации схемы.
  • Легкость изменения и обновления. В случае необходимости изменения дизайна, изменения могут быть легко внесены в код. Это значительно экономит время по сравнению с обновлением схемы, где каждое изменение может потребовать полной переработки. Разработчики могут анализировать и отлаживать код, что гораздо удобнее и быстрее, чем изучение схем.
  • Упрощение процесса сопровождения и документации, а также читаемость. Код на Verilog может быть легче читаем и понятен другим инженерам, изучение схемы, что упрощает поддержку и сопровождение проектов. Документирование проекта на языках описания аппаратуры позволяет лучше структурировать и документировать проект, что делает его понятнее.
  • Интеграция с другими инструментами. Проект реализованный, например, Verilog легче переносить (интегрировать) в средах автоматизированного проектирования (CAD), что позволяет эффективно разрабатывать, моделировать и синтезировать сложные цифровые устройства.
  • Скорость реализации проекта.
  • В литературе можно встретить описание языков описания аппаратуры как составной системы из двух компонент: общеалгоритмической и проблемно-ориентированной.

    Алгоритмическая компонента языка Verilog заключается в схожести его семантики и синтаксиса с Си подобными языками. Язык содержит операторы, типы данных, процедурные блоки и функции.

    Проблемно-ориентированная компонента заключается в наличии интерфейсов, в том числе данных физического типа, сигналов, конкретизации применяемых компонентов.

    Освоение языка можно начать с формирования представления о зарезервированных словах.

    В языке Verilog определены следующие зарезервированные слова, применяемые при реализации описания схем - модулей. Соответственно для применения в качестве имен переменных, констант их использовать нельзя. Зарезервированные слова Verilog приведены в таблице 1.1.

    always

    and

    assign

    attribute

    automatic

    begin

    buf

    bufif0

    bufif1

    case

    casex

    casez

    cell

    cmos

    config

    deassign

    default

    defparam

    disable

    edge

    else

    end

    endattribute

    endcase

    endconfig

    endfunction realtime

    endgenerate

    endmodule

    endprimitive

    endspecify

    endtable

    endtask

    event

    for

    force

    forever

    fork

    function

    generate

    genvar

    highz0

    highz1

    if

    ifnone

    incdir

    include

    instance

    initial

    inout

    input

    integer

    join

    large

    liblist

    library

    localparam

    micromodule

    medium

    module

    nand

    negedge

    nmos

    nor

    not

    notif0

    notif1

    nowshowcancelled

    or

    output

    parameter

    pmos

    posedge

    primitive

    pull0

    pull1

    pulldown

    pullup

    pulsestyle_ondetect

    pulsestyle_onevent

    remos

    real

    reg

    release

    repeat

    rnmos

    rpmos

    rtran

    rtranif0

    rtranif1

    scalared

    signed

    small

    specify

    showcancelled

    specparam

    strength

    strong0

    strong1

    supply0 s

    upply1

    table

    task

    time

    tran

    tranif0

    tranif1

    tri

    tri0

    tri1

    triand

    trior

    trireg

    unsigned

    use

    vectored

    wait

    wand

    weak0

    weak1

    while

    wire

    wor

    xnor

    xor

    Необходимо закрепить базовые понятия, которыми необходимо руководствоваться при описании аппаратуры:

  • В Verilog имя (идентификатор) - последовательность букв и цифр, знаков "$" и "_", причем начинаться оно обязано не с цифры. Регистр имеет значение. Если начальный символ - "\", то следом за ним может идти любая последовательность символов. Все, что до пробела, будет считаться корректным именем. Например: "Namee", "nAmee", "$Char", "\c+Ha^ra".
  • При написании программного кода разработчик должен оставлять комментарии. В Verilog также существуют средства обозначения комментариев. Комментарии делятся на:

  • однострочные (//);
  • блочные (/* текст комментария или часть программы */).
  • Однострочными комментариями можно закомментировать часть одной строки или всю строку полностью.

  • Пунктуация - пробелы игнорируются. Точка с запятой используется для обозначения конца командной строки. Запятые, как правило, используются для отдельных элементов в списке.
  • Описание каждого объекта аппаратуры осуществляется в модулях и размещается между зарезервированными словами: module и endmodule.

    Создаваемые объекты должны иметь интерфейсы - порты.

    Порты в Verilog бывают трёх типов:

  • Input - вход;
  • Output - выход;
  • Inout - двунаправленный.
  • Порт объявляется следующим образом: тип [разрядность] имя порта;.

    Если не задана спецификация диапазона, например input [2:0] a, то считается, что порт имеет ширину одного бита, а передаваемые сигналы считаются скалярными. Если порт представляет собой шину, то есть имеет диапазон, то передаваемые сигналы считаются векторными.

    Порты могут иметь в объявлении константные выражения, через зарезервированное слова parameter. Также могут объявляться внутренние цепи через зарезервированное слово wire.

    Существует еще один тип источника сигнала reg. Данный тип при описании комбинационной логики ведет себя как переменная - провод wire. При проектировании синхронных схем сигнал reg способен сохранять значение, т.е. является триггером или регистром.

    Сигналы или переменные могут быть представлены следующими логическими уровнями:

  • 0: ноль, логический низкий уровень, "ложно", "земля" (zero, logic low, false, ground);
  • 1: единица, логический высокий уровень, "истина", "питание" (one, logic high, power);
  • X: неизвестное значение (unknown);
  • Z: высокий импеданс, неподключенный сигнал, третье состояние (high impedance, unconnected, tri-state).
  • Пример описания модуля приведен в листинге 1.1, где красным выделены зарезервированные слова, зеленым - пользовательские имена и коментарии, синим функционал.

    	module name_module 
    	#(parameter M=4) // константа
    (input [3:0] A,B, // четырехразрядные входы А и B 
    	input cin,// однопроводная линия
    	output  [M-1:0] S, //выход использующий для определения разрядности //константу 
    	output co); //выход линия
    	wire [4:0] sum; // внутренние сигналы
    assign sum = A + B + cin; // Суммируем A, B и cin 
    assign S = sum[M-1:0]; // Выход S - последние M разрядов суммы 
    assign co = sum[4]; // Выход переноса 
    endmodule
    

    1.1. Основы проектирования и верификации модулей

    Для начала решения проблемно-ориентированных задач, следует остановиться на важнейшем разделе любого проекта - определение этапов выполнения проекта:

  • Постановка задачи и формирование технического задания.
  • Формализация задания и выполнение математической модели.
  • Ввод описания проекта (выбор инструментов и способа описания, непосредственно описание проекта);
  • Построение моделирующего алгоритма
  • Создание тестового окружения и верификация проекта.
  • Отладка и устранение выявленных ошибок, выполнение повторных тестов.
  • Анализ результатов и их документирование.
  • Передача результатов заказчику.
  • Сформируем следующую задачу: необходимо разработать и реализовать схему с тремя входами для мажоритарного контроля, используя язык описания аппаратуры Verilog. Схема должна сравнивать три входа и выдавать сигнал, равный лог. "1" если два или более входов равны лог. "1".

    Уточним требования к интерфейсу проектируемой схемы и уровням сигналов реакции:

  • Входные сигналы:

  • a: первый вход (сигнал 1 бит);
  • b: второй вход (сигнал 1 бит);
  • c: третий вход (сигнал 1 бит);
  • Выходной сигнал - y, на котором установится лог. "1" если как минимум на двух входах будет присутствовать лог "1".
  • Выполним математическое моделирование. Для этого сформируем по условиям таблицу истинности (таблица 1.2).

    п/п Входы Выход
    A b c y
    1 0 0 0 0
    2 0 0 1 0
    3 0 1 0 0
    4 0 1 1 1
    5 1 0 0 0
    6 1 0 1 1
    7 1 1 0 1
    8 1 1 1 1

    Проведем анализ таблицы 1.2 истинности и определим строки, в которых комбинация входных сигналов обеспечит лог. "1" на выходе. В данном случае это 4, 6,7,8 строки. Выпишем их:

  • (a=1,b=1,c=0);
  • (a=1,b=0,c=1);
  • (a=0,b=1,c=1);
  • (a=1,b=1,c=1);
  • Сформируем СКНФ из данных:

    $$y=a*b*\bar c+a*\bar b*c+]bar a*b*c+a*b*c$$

    После преобразований формула примет вид:

    $$y=(a*b)+(b*c)+(a*c)$$

    Введем проект на заявленном языке Verilog. Определим имя модуля как major, тип сигнала интерфейса - wire. Имена сигналов были заданы в условии.

    Используя процедурный оператор assign, введем функцию, описанную выше на языке Verilog как показано в листинге 1.2.

    module major ( // начало модуля
        input wire a, // первый вход
        input wire b, // второй вход
        input wire c, // третий вход
        output wire y // выход мажоритарного значения
    );
    assign y = (a  b) | (b  c) | (c  a); // реализуемая функция
    endmodule // окончание модуля
    

    1.1.1. Верификация

    При создании цифровых устройств одним из сложных и самых трудоемких этапов является процесс верификации. Данный этап может отвлекать от 50 до 80% всего времени выполнения проекта.

    Верификация - это процесс установления соответствия созданного устройства, техническим условиям спецификации из технического задания.

    В рамках верификации выполняются различные тесты, причем могут вноситься изменения в конечную спецификацию устройства.

    В рамках выполнения верификации одним из этапов является процедура функциональной верификации - проверка на наличие ошибок в проекте. Для выполнения функциональной верификации применим инструменты симуляции работы схемы.

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

    Для проверки разработанного кода перенесем его в среду проектирования Intel Quartus.

  • Создадим проект с именем major.
  • Создадим новый файл Verilog HDL и введем код из листинга, сохраним файл с именем major.v.
  • Выполним компиляцию проекта в основном меню среды "Processing" - "Start Compilation"
  • Далее воспользуемся инструментом для ввода тестовых векторов, отслеживания изменения внутренних линий и состояния выходных портов - Waveform Editor. Для этого пройдя в меню "File" - "New", выберем в разделе "Verification/Debugging Files" пункт "University Program VWF".
  • В открывшейся форме (рисунок 1.1), добавим входы и выход модуля через меню "Edit" - "Insert" - "Insert Node or Bus" (рисунок 1.2). Нажав на кнопку "Node Finder", перейдем на форму выбора сигналов. Так как мы выбираем все сигналы, нажмем на кнопку "List". Исследуемые сигналы (все) переместим в поле "Selected Nodes", нажав на кнопку >> (рисунок 1.3).

    (рис 1.1) (рис 1.2) (рис 1.3)
  • Необходимо исключить один из параметров работы симулятора - noopt. Для этого перейти в меню "Simulation" - "Simulation Settings".

    В открывшемся окне, найдем данный параметр и удалим (рисунок 1.4).

    (рис 1.4)
  • Далее выполняется создание тестовых уровней сигналов. Для этого левой кнопкой мыши выбирается временной отрезок (одна или несколько клеток). После выбора он заливается синим цветом. Далее необходимо в меню инструментов выбрать уровень сигнала, в данном случае выбрать лог. "1" -.
  • Исходя из таблицы истинности формируем тестовые сигналы как показано на рисунке 1.5.
  • Далее выполняется функциональная симуляция через меню "Simulation" - "Run Functional Simulation". Полученную диаграмму (рисунок 1.6) необходимо сверить с заданными в техническом задании условиями, а также с таблицей истинности.
  • (рис 1.5) (рис 1.6)

    Более совершенные методы верификации подразумевают применение тестирующего оборудования или отладочного модуля, именуемого testbench. Testbench генерирует набор сигналов для проектируемого устройства, а затем принимает их для последующего анализа.

    Стратегия работы с тестовым окружением - поочередная подача восьми возможных комбинаций на входы a,b,c

    Для создания testbench необходимо рассмотреть основы синтаксиса данных файлов.

    Первая строка кода testbench может содержать директиву масштаба модельного времени, определяющая значение залежек модели, которая начинается с обратной кавычки: `timescale. С этой директивой указываются временные параметры: N1 - определяет единицы времени задержки сигналов, следующих за символом #; N2 - точность расчета.

    Оба параметра указываются в наносекундах или пикосекундах и могут принимать значения только 1, 10 или 100. По умолчанию назначаются ps.

    Пример: `timescale 1ns/1ns

    В следующей строке тестового модуля указывается ключевое слово module и имя модуля с обязательной приставкой tb, указывающей на то, что это тестовый модуль проекта.

    Так как это тестовый модуль, то он не имеет портов. В него вставляется тестируемый модуль и входы/ выходы тестируемого модуля взаимодействуют с переменными типа reg и wire.

    Например, для тестируемого модуля будет применено следующее объявление:

    reg a;
    reg b;
    reg c;
    wire y;
    

    Следующей частью кода является инстанцирование тестируемого модуля в тестовый модуль. При этом в списке портов устанавливается соответствие между портами тестового и тестируемого модулей. Модуль testbench в общем случае, может иметь отличные от тестируемого имена входов/выходов.

    После имени тестируемого модуля должен быть указан тип подсистемы, которая тестируется:

  • DUT (device under test), обозначает любое устройство или компонент, который тестируется. Это может быть целая система или отдельный модуль, в зависимости от уровня верификации.
  • UUT (unit under test), это подмножество DUT, обычно подчеркивающее конкретный модуль или блок, который тестируется в рамках более крупного устройства или системы.
  • Пример инстанцирования для рассматриваемого примера:

    major uut (
        .a(a),
        .b(b),
        .c(c)
    

    Далее с помощью конструкций, определяемых ключевыми словами initial begin…end выполняется моделирование.

    Конструкции содержат описания начальных значений и дальнейшего поведения входных сигналов во времени. Блок initial задает симулятору точку, с которой начинается работа. Следует отметить, что тестовый модуль без блока initial не работает.

    Следующим этапом указываются варианты поведения сигналов и указание временных единиц (задержки) для их смены.

    Также можно применять команды для вывода информации во время симуляции:

  • $display, выводит информацию только в момент вызова;
  • $monitor, выводит информацию каждый раз при изменении отслеживаемых переменных.
  • Пример: $monitor("a=%b, b=%b, c=%b, y=%b", $time, a, b, c, y);

    Далее указывается одна из конструкций системной директивы $finish, которая завершает процесс моделирования. И наконец, ключевое слово endmodule указывает на окончание описания тестового модуля.

    В листинге 1.3 приведен исходный код тестового модуля tb_major

    `timescale 1ns/1ns
    module tb_major;
    reg a;
    reg b;
    reg c;
    wire y;
    major uut (
        .a(a),
        .b(b),
        .c(c),
        .y(y)
    );
    
    initial begin
        
        $monitor("a=%b, b=%b, c=%b, y=%b", $time, a, b, c, y);
        
        a = 0; b = 0; c = 0;//y=0  
        #10; 
        a = 0; b = 0; c = 1;//y=0  
        #10; 
        a = 0; b = 1; c = 0;//y=0 
        #10; 
        a = 0; b = 1; c = 1;//y=1 
        #10; 
        a = 1; b = 0; c = 0;//y=0 
        #10; 
        a = 1; b = 0; c = 1;//y=1
        #10; 
        a = 1; b = 1; c = 0;//y=1
        #10; 
        a = 1; b = 1; c = 1;//y=1
        #10; 
          $finish;
    end
    endmodule
    

    Для реализации верификации с использованием созданного тестового модуля необходимо выполнить ряд манипуляций с проектом.

  • Файл testbench сохранить в каталоге проекта под именем tb_major.v;
  • Перейти в меню "Tools" - "Options". В открывшемся окне, перейти на вкладку EDA Tool Options (рисунок 1.7). В поле Modelsim-Altera указать путь к каталогу симулятора (по умолчанию: C:\intelFPGA_lite\20.1\modelsim_ase\win32aloem). Нажать кнопку ОК.
  • Перейти в меню "Assigments" - "Settings". В открывшемся окне, перейти в раздел "EDA Tool Settings". В строке "Simulation" для столбца "Tool Name" выбрать Modelsim-Altera. В столбце "Format(s) " выбрать Verilog HDL (рисунок 1.8). Нажать кнопки Apply и OK.

    (рис 1.7) (рис 1.8)
  • Далее в меню пройти в меню "Assigments" - "Settings". В открывшемся окне, перейти в подраздел "Simulation" раздела "EDA Tool Settings". В окне настроек установить метку "Compile test bench" (рисунок 1.9).

    (рис 1.9)
  • Нажать кнопку Test Benches. В новом окне (рисунок 1.10), нажать накнопку New.

    (рис 1.10)
  • В диалоговом окне, приведенном на рисунке 1.11, в поле Test bench name ввести tb_major. Далее добавить файл, нажав на кнопку "… " поля "File name". Выбрать файл и нажать кнопку Add, затем кнопку ОК.

    (рис 1.11)
  • Вернувшись в окно Test Benches, убедиться, что файл добавлен (рисунок 1.12). Далее нажать OK.

    (рис 1.12)
  • В окне "Settings" нажать кнопки Apply и OK.
  • Выполнить компиляцию проекта. В случае успешной компиляции запустить симуляцию проекта ("Tools" - "Run Simulation Tool" - "RTL Simulation"). Откроется инструмент ModelSim.
  • Результат симуляции отобразится в виде диаграммы на панели Wave (рисунок 1.13). Текстовые сообщения выводятся в панели Transcript.
  • Убедившись в верности отображаемых данных, можно окончить работу симуляции и завершить работу программы ModelSim.
  • (рис 1.13)

    Необходимо отметить, что качественный testbench должен содержать код самопроверки, то есть операторы, отслеживающие возникновение ошибки в ходе работы.

    2. Представление целых и действительных чисел в Verilog

    Для представления целых чисел применяется следующий формат записи: size'base value, где size - размер, определяющий систему счисления, в которой представлено число, base - система счисления числа, value - непосредственное значение.

    Для обозначения базы применяются следующие символы:

  • 'd или 'D - десятичные числа;
  • 'b или 'B - двоичные числа;
  • 'o или 'O - восьмеричные числа;
  • 'h или 'H - шестнадцатеричные числа;
  • Примеры:

    4'b1010 - двоичное четырёхразрядное число (в десятичной системе 10);

    6'o71 - шестиразрядное восьмеричное число;

    8'd127 - восьмиразрядное десятичное число 127;

    127 - десятичное число (по умолчанию).

    Для представления действительных чисел в Verilog применяется запись либо c десятичной точкой, либо в экспоненциальном виде. Запись с точкой имеет вид: value_i.value_f, где: value_i - целая часть, value_f - дробная часть

    Примеры:

    1.8
    3.8e10 // e или E для равно $$3,8*10^{10}$$
    2.1e-9// 2,1*$$10^{-9}$$
    

    3. Выражения

    Выражения и операции на языке Verilog, применяющие примитивы относятся к следующим видам:

  • логические операции, например, a b - логическое "И";
  • арифметические операции, например, a + b - это сложение двух чисел одинаковой разрядности с переполнением;
  • побитные операции, например, a b - это побитное "И" двух битовых массивов одинаковой длины;
  • отношения, например, a<b возвращает логическую 1, если число, двоичная запись которого есть a, меньше такового для b, и логический 0 иначе.
  • конкатенации, например, {a, b} - битовый массив, составленный из a и b;
  • редукции, например, a - имеет логическую 1, если все биты a равны лог "1", и логический 0 иначе;
  • условия,например, cond ? a : b работает как в C++. cond должно иметь логическое значение, a и b должны иметь одинаковое число бит.
  • В таблице 1.3 приведены операции языка Verilog для построения выражений.

    Побитные операторы
    ~ инверсия
    побитное "И"
    | побитное "ИЛИ"
    ^ побитное "Исключающее ИЛИ"
    ~^ или ^~ побитное "Исключающее ИЛИ НЕ"
    Логические операторы
    ! логическое "НЕ"
    AND логическое "И"
    || OR логическое "ИЛИ"
    Редукция
    редуцированное "И"
    ~ редуцированное "НЕ-И"
    | редуцированное "ИЛИ"
    ~| редуцированное "НЕ-ИЛИ"
    ^ редуцированное "Исключающее ИЛИ"
    ~^ или ^~ редуцированное "Исключающее ИЛИ НЕ"
    Арифметические операторы
    + сложение
    - вычитание
    * умножение
    / деление
    Отношение
    > больше
    < меньше
    >= больше либо равно
    <= меньше либо равно
    = = логическое равенство
    != логическое неравно
    = = = 4 state логическое равенство
    != = 4 state логическое неравно
    Операции сдвига
    >> логический сдвиг вправо
    << логический сдвиг влево
    >>> арифметический сдвиг вправо
    <<< арифметический сдвиг влево
    Разное
    { , } склеивание
    {n{m}} копирует m значение n раз
    ? : условие

    В листинге 1.3 приведен пример организации комбинационной схемы сравнения, использующей операторы отношения.

    module comparator (
    input [7:0] A, B,
    output O_EQ, O_NE, O_BR, O_MR, O_BOL, O_MEN);
    assign O_EQ = A == B;
    assign O_NE = A != B;
    assign O_BR = A >= B;
    assign O_MR = A <= B;
    assign O_BOL = A >B;
    assign O_MEN = A < B;
    endmodule
    

    4. Оператор непрерывного присваивания assign

    Оператор assign в Verilog предназначен для описания непрерывных присвоений в структуре цифровых схем. Этот оператор используется для связывания значений между сигналами и переменными.

    Назначение оператора assign:

  • Позволяет задавать непрерывные присвоения между проводами и переменными. Это означает, что результат выражения всегда будет обновляться автоматически при изменении входных сигналов.
  • С помощью assign можно описываются логические цепи и комбинационные схемы.
  • В листинге 1.4 дается пример применения оператора assign. На рисунке 1.14 можно наблюдать результат на уровне RTL.

    module logic_operators
    ( input [3:0] a, b, // объявление входных векторных портов 
    output [3:0] y, // объявление выходного векторного порта 
    output z); 
    assign y = a  b; // побитная операция " И" над входами
    assign z =  y; // редукция, объединение выходов y через операцию "И" и получение выхода //Z
    endmodule
    
    (рис 1.14)

    Возможно присваивание при объявлении, например, wire [2:0] z = x + y;.

    5. Процедурные блоки initial и always

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

    В симуляциях блоки initial выполняются только один раз в момент старта симуляции. Это делает их идеальными для настройки начальных значений переменных и запуск тестов.

    Блок always в Verilog предназначен для описания синхронных и асинхронных схем, а также для сложных комбинационных схем. Он используется для определения логики управления, где состояние выходных сигналов зависит от состояния входных сигналов.

    Пример: always @ (posedge clock) . Приведенный код позволяет запускать логику только по фронту тактового сигнала.

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

    В асинхронных схемах always применяется для описания поведения схем, которые реагируют на изменения входных сигналов немедленно, без учета тактового сигнала.

    Общий вид записи: блока always @(<сигналы>) <действия>, где <сигналы> - это список всех входных сигналов, к которым чувствителен блок. Это список входных сигналов, изменение которых влияет на выходные сигналы этого блока. Выполнение оператора или операторов в блоке <действия> будет приостановлено, до тех пор, пока не произойдет изменение какого-либо из сигналов в списке чувствительности.

    В списке чувствительности имена входных сигналов разделяются ключевым словом "or" , например, always @(a or b or d) <statements>.

    Иногда гораздо проще и надежней включать в список чувствительности все сигналы. Это делается аналогично примеру: always @* <statements>.

    Для присвоения значения сигналам в процедурных блоках initial и always применяются типы данных из класса переменных reg.

    Как было отмечено выше reg - переменная, занимающая в памяти определенное число битов (диапазон *… : …+), по умолчанию - 1 бит.

    Примеры объявления переменных:

    reg a, b, c ; // три скалярные однобитовые переменные

    reg signed [7:0] d1, d2; // две 8-битовые переменные со знаком

    reg [7:0] Q[0:3][0:15] ; // двумерный массив 8-битовых переменных

    reg clock = 0, reset=1; // две переменные типа reg с начальными значениями.

    При использовании конструкции always для комбинационных и асинхронных последовательностных схем применяется оператор блокирующего присваивания (=). Операторы выполняются один за другим. Пример:

    always @(*) //анализируем все сигналы
    begin
    	y=ab;
    	z= a||b;
    end
    

    Для проектирования последовательностной синхронной логики в блоке always применяется неблокирующее присваивание (<=). В данном случае список чувствительности содержит сигналы от значения которых зависит, когда произойдет сохранение значения переменной.

    Пример:

    wire d, clk;
    reg q;
    	always @ (posedge clk)
    	q<=d;
    

    Пример неблокирующего присваивания для получения последовательного регистра приведен в листинге 1.5.

    module nonb_trigger (
    input d,clk,
    output reg q,q1,q2,q3);
    always @(posedge clk)
    begin
    	q<=d;
    	q1<=q;
    	q2<=q1;
    	q3<=q2;
    end
    endmodule
    

    Из описания модуля в листинге видно, что значения всех переменных формируются по фронту clk. Первый оператор присваивает переменной q значение с входа d, но при этом другие присваивания не блокируются. Так как значение d еще неизвестно, а оно будет известно только в следующем такте фронта clk, поэтому следует что значение на входе q1 изменится на следующем такте.

    RTL представление модуля представлено на рисунке 1.15.

    (рис 1.15)

    Для описания условий в Verilog применяются условия стандартные для высокоуровневых языков программирования. Пример приведен в листинге 1.4.

    Общий вид записи:

     if(<условие>)
     	<действие1>; 
    else 
    <действие 2>;
    

    Пример, описывающий применение данной конструкции, показан для D-триггера в листинге 1.6. Если на вход rst поступает лог. "0", триггер сбрасывается. В противном случае происходит неблокирующее присваивание переменной q данных с входа d по фронту сигнала clk.

    always @(posedge clk or negedge rst_n) // Анализируем два сигнала
    begin 
    if (!rst_n) // если вход rst_n переходит в 0 - спад 
    q <= 1'b0; // сбрасываем выход 
     else 
    q <= d; // иначе на выход поступают данные или с переменной d
    end
    

    Также в Verilog возможно применение конструкции else if, то есть проверка работы предыдущего условия. Если оно не исполнено, то осуществляется обработка условия в конструкции eslse-if, последующие конструкции не обрабатываются.

    В листинге 1.7 приведен код для реализации двухразрядного дешифратора с применением конструкции eslse-if. На рисунке 1.16 приведено RTL представление модуля дешифратора.

      module shifr (
        input [1:0] in,     // вход (2 разряда)
        output reg [3:0] out // выход (4 разряда)
    );
    // проверка изменения сигналов на входе
    always @(*) begin
        // сброс выхода
        out = 4'b0000; 
        // Дешифрация входного кода
        if (in == 2'b00) 
            out = 4'b0001; // активен выход 0
         else if (in == 2'b01) 
            out = 4'b0010; // активен выход 1
         else if (in == 2'b10) 
            out = 4'b0100; // активен выход 2
         else if (in == 2'b11) 
            out = 4'b1000; // активен выход 3
    		else out=4'bxxxx;
        end
    endmodule
    
    (рис 1.16)

    Использование оператора if вводит большие задержки, потому что подразумевает вычисление выражения для сигналов (при моделировании работы схемы) в том порядке, в котором они появляются в модели (выражение в конечной ветви оператора if вычисляется последним).

    Правильным и более выразительным вариантом проверки входных условий может быть метод case, который позволяет сделать выбор из многих вариантов (на языке схемотехники мультиплексор со многими входами).

    Конструкция case схожа по синтаксису и формату применения с высокоуровневыми языками программирования.

    Базовый синтаксис следующий:

    case (<проверяемый операнд>)
      option1: <действие>;
      option2: <действие >;
      default:  <если не работают условия выше>;   
    endcase
    

    В разделе "Комбинационные схемы" данного курса данная конструкция применяется при описании дешифратора семисегментного индикатора.

    В листинге 1.8 приведен пример работы с case для описанного выше двухразрядного дешифратора.

    module shifr1 (
        input [1:0] in,       //вход (2 разряда)
        output reg [3:0] out  // выход (4 разряда)
    );
    
    // проверка изменения сигналов на входе
    always @(*) begin
        // сброс выходов
        out = 4'b0000; 
        
        // Дешифрация входного кода
        case (in)
            2'b00: out = 4'b0001; // активен выход 0
            2'b01: out = 4'b0010; // активен выход 1
            2'b10: out = 4'b0100; // активен выход 2
            2'b11: out = 4'b1000; // активен выход 3
            default: out = 4'b0000; // по умолчанию сброшен
        endcase
    end
    
    endmodule
    

    На рисунке 1.17 приведена RTL схема данного модуля. Как видно из рисунка схема получила вид дешифратора.

    (рис 1.17)

    6. Функции в языке Verilog

    Для сокращения кода описываемого узла или устройства можно сводить повторяющиеся блоки в функции. Синтаксис функций схож с языком С.

    Базовый синтаксис следующий:

    Function [<возвращаемый тип>] <имя> ([список портов])
     <действия> 
    Endfunction
    

    В листинге 1.9 приведен пример функции, реализующей 8-разрядный сумматора.

    function [7:0] sum (input [7:0] a,b);// объявление функции портов и выходного тип данных и //аргумента
    begin 
    sum=a+b;// реализуемая функция 
    end 
    endfunction
    

    На данном этапе обзор языка Verilog и его основных конструкций закончен.

    С объемными материалами по разработке на FPGA с использованием Verilog можно ознакомиться:

  • на курсе "Введение в FPGA и Verilog". (НИУ МФТИ).
  • В рамках "Школы синтеза цифровых схем"
  • Также рекомендуется изучение и применение дополнительной литературы и информационных источников:

  • Соловьев В.В. Язык Verilog в проектировании встраиваемых систем на FPGA. - М.: Горячая линия - Телеком, 2022. - 440с.: ил.
  • Акчурин А.Д., Юсупов К.М. Программирование на языке Verilog [Электронный ресурс] (Дата обращения 08.08.2024)
  • Филиал МИРЭА в г. Фрязино Методические рекомендации для проведения лабораторных занятий по курсу "Цифровые системы" МЕ2200 [Электронный ресурс] (Дата обращения 15.07.2024)
  • Сайт marsohod.org [Электронный ресурс] (Дата обращения 12.07.2024)
  • Дополнительная литература

    по среде Logisim

  • Скаков П.С., Яковлева В.Е. Архитектура ЭВМ: учебно-методическое пособие по лабораторным работам. - Санкт-Петербург: Университет ИТМО, 2023. - 99 с. - экз. [Электронный ресурс] (Дата обращения 15.09.2024)
  • Попов Д.И., Лилов И.П. "Организация ЭВМ. Лабораторные работы в программе Logisim" Москва, 2011 [Электронный ресурс] (Дата обращения 15.09.2024)
  • George Self Logisim Lab manual [Электронный ресурс] (Дата обращения 31.07.2024)
  • По языку Verilog HDL и среде Intel Quartus Prime Lite Edition

  • Соловьев В.В. Язык Verilog в проектировании встраиваемых систем на FPGA. - М.: Горячая линия - Телеком, 2022. - 440с.: ил.
  • Акчурин А.Д., Юсупов К.М. Программирование на языке Verilog [Электронный ресурс] (Дата обращения 08.08.2024)
  • Филиал МИРЭА в г. Фрязино Методические рекомендации для проведения лабораторных занятий по курсу "Цифровые системы" МЕ2200 [Электронный ресурс] (Дата обращения 15.07.2024)
  • Сайт marsohod.org [Электронный ресурс] (Дата обращения 12.07.2024)
  • Вернуться к учебному плану