СОДЕРЖАНИЕ Введение ................................................................................................................... 4 1 ТЕОРЕТИЧЕСКИЕ ОСНОВЫ РАБОТЫ УСТРОЙСТВА............................... 6 1.1 I²C..................................................................................................................... 6 1.2 Принцип подключения .................................................................................. 6 1.3 Принцип работы ............................................................................................. 7 1.3.1 Состояние старт и стоп .......................................................................... 7 1.3.2 Подтверждение ....................................................................................... 8 1.3.3 Синхронизация ....................................................................................... 8 1.4 Адресация в шине I²C .................................................................................... 9 1.5 Описание выводов ПЛИС и форматов данных ......................................... 11 2 VHDL-ОПИСАНИЕ МИКРОЭЛЕКТРОННОГО УСТРОЙСТВА ................ 13 3 ТЕСТИРОВАНИЕ РАБОТЫ МИКРОЭЛЕКТРОННОГО УСТРОЙСТВА.. 16 4 АППАРАТНАЯ РЕАЛИЗАЦИЯ МИКРОЭЛЕКТРОННОГО УСТРОЙСТВА ................................................................................................................................. 17 4.1 Обоснование выбора ПЛИС и микросхемы конфигурационного ПЗУ . 17 4.2 Использованные ресурсы ПЛИС ................................................................ 18 4.3 Оценка потребляемой устройством мощности ......................................... 22 Заключение ............................................................................................................ 23 Список используемых источников ...................................................................... 24 Приложение А - Реализация Master на языке VHDL ........................................ 25 Приложение Б - Тестирование Master на языке VHDL ..................................... 30 Приложение B - Реализация Slave на языке VHDL ........................................... 33 Приложение Г - Тестирование Slave на языке VHDL ....................................... 39 Приложение Г - Тестирование Master - Slave на языке C ................................. 48 Разработка безопасного микропроцессорного устройства Изм. Лист Разраб. Руководит. . Реценз. Н. контр. Утв. № докум. Подпись Дата Записка пояснительная Лит. Лист Листов 3 Кафедра «ИУСиТ» 1 Введение Системы автоматизированного проектирования (САПР) вычислительной техники, как правило, имеют средства ввода и редактирования схем. Однако три десятилетия назад при разработке СБИС начали отказываться от схемного проектирования. При разработке электрических схем этап проектирования средств вычислительной техники – это работа, связанная с определёнными трудностями: большими трудозатратами, контролем правильности и соответствия задуманному проекту, необходимостью чёткого и ёмкого описания созданных схем, трудностями с их сопровождением и модернизацией. Язык «Very high speed integrated circuits Hardware Description Language» (VHDL) был разработан в 1983 г. по заказу Министерства обороны США с целью формального описания логических схем для всех этапов разработки электронных систем, от модулей микросхем и до крупных вычислительных систем. Он является стандартным языком с 1987 г. Стандартом 1993 г. закреплены многие его усовершенствования. Наряду с языком Verilog он является базовым языком при разработке аппаратуры современных вычислительных систем. Преимущества VHDL перед схемным проектированием весьма значительны. Это и универсальность, и надёжность, и портативность, и возможность самодокументирования. Проекты, написанные на VHDL, предназначены для исполнения в программируемой логической интегральной схеме (ПЛИС). Размещение всего оборудования на одном кристалле является очень выгодным, благодаря уменьшению общей стоимости, числа необходимых микросхем, энергопотребления, повышению надёжности. Таким образом, на одном кристалле размещается не только конкретное функциональное устройство, например, центральный микропроцессор, но и другие, такие как АЦП, ОЗУ, ПЗУ, блоки цифровой обработки сигналов, интерфейсные узлы и т.п., дополняющие его до законченной системы блоков. Поэтому такое вычислительное устройство (ВУ) принято называть «System On the Chip» (SOC) – системой на кристалле (СНК). СНК это, как правило, заказная СБИС. Чтобы разработка СНК себя окупила, необходимо реализовать десятки и сотни тысяч СБИС. Проект ВУ, реализованный на ПЛИС, может быть выгодным при партиях в десятки и сотни экземпляров, благодаря дешевизне разработки и производства. Разработка такого ВУ длится как минимум в два раза быстрее, чем проектирование СБИС. Это обусловило бурное распространение ПЛИС как элементной базы СНК. В курсовой работе разработано специализированное микроэлектронное устройство, реализующее алгоритм послеовательной передачи данных I2C. В задачи курсовой работы входит: рассмотрение теоретических основ работы алгоритма послеовательной передачи данных I2C, разработка алгоритма функционирования устройства, описание алгоритма на языке VHDL, выбор оптимального ПЛИС под заданные цели, синтез VHDL-описания и размещение Разработка безопасного микропроцессорного устройства Изм. Лист № докум. Подпись Дата Лист 4 устройства на кристалле, а также тестирование разработанного микроэлектронного устройства. Разработка безопасного микропроцессорного устройства Изм. Лист № докум. Подпись Дата Лист 5 1 ТЕОРЕТИЧЕСКИЕ ОСНОВЫ РАБОТЫ УСТРОЙСТВА 1.1 I²C I²C (IIC, англ. Inter-Integrated Circuit) — последовательная асимметричная шина для связи между интегральными схемами внутри электронных приборов. Использует две двунаправленные линии связи (SDA и SCL), применяется для соединения низкоскоростных периферийных компонентов с процессорами и микроконтроллерами (например, на материнских платах, во встраиваемых системах, в мобильных телефонах). 1.2 Принцип подключения Данные передаются по двум проводам — проводу данных и проводу тактов. Есть ведущий (master) и ведомый (slave), такты генерирует master, ведомый лишь «поддакивает» при приёме байта. Всего на одной двухпроводной шине может быть до 127 устройств. Рисунок 1 – Принцип подключения шины I2C Пример схемотехники с одним главным микроконтроллером (μC Master) и тремя подчинёнными (slave) устройствами (ADC — аналого-цифровой преобразователь, DAC — цифро-аналоговый преобразователь и второй (подчиненный) микроконтроллер (μC Slave)), подтягивающими резисторами Rp. Разработка безопасного микропроцессорного устройства Изм. Лист № докум. Подпись Дата Лист 6 1.3 Принцип работы Рисунок 2 – Принцип работы шины I2C I²C использует две двунаправленные линии, подтянутые к напряжению питания и управляемые через открытый коллектор или открытый сток — последовательная линия данных (SDA, англ. Serial DAta) и последовательная линия тактирования (SCL, англ. Serial CLock). Стандартные напряжения +5 В или +3,3 В, однако допускаются и другие. Классическая адресация включает 7-битное адресное пространство с 16 зарезервированными адресами. Это означает, что разработчикам доступно до 112 свободных адресов для подключения периферии на одну шину. Основной режим работы — 100 кбит/с; 10 кбит/с в режиме работы с пониженной скоростью. Также немаловажно, что стандарт допускает приостановку тактирования для работы с медленными устройствами. 1.3.1 Состояние старт и стоп Процедура обмена начинается с того, что ведущий формирует состояние СТАРТ: генерирует переход сигнала линии SDA из ВЫСОКОГО состояния в НИЗКОЕ при ВЫСОКОМ уровне на линии SCL. Этот переход воспринимается всеми устройствами, подключенными к шине, как признак начала процедуры обмена. Генерация синхросигнала — это всегда обязанность ведущего; каждый ведущий генерирует свой собственный сигнал синхронизации при пересылке данных по шине. Процедура обмена завершается тем, что ведущий формирует состояние СТОП — переход состояния линии SDA из НИЗКОГО состояния в ВЫСОКОЕ при ВЫСОКОМ состоянии линии SCL. Состояния СТАРТ и СТОП всегда вырабатываются ведущим. Считается, что шина занята после фиксации состояния СТАРТ. Шина считается освободившейся через некоторое время после фиксации состояния СТОП. При передаче посылок по шине I²C каждый ведущий генерирует свой синхросигнал на линии SCL. После формирования состояния СТАРТ ведущий опускает состояние линии SCL в НИЗКОЕ состояние и выставляет на линию SDA старший бит первого байта сообщения. Количество байт в сообщении не ограничено. Спецификация шины I²C разрешает изменения на линии SDA только при НИЗКОМ уровне сигнала на линии SCL. Данные действительны и должны оставаться стабильными только во время ВЫСОКОГО состояния синхроимпульса. Для подтверждения приёма байта от ведущегопередатчика ведомым-приёмником в спецификации протокола обмена по шине I²C Разработка безопасного микропроцессорного устройства Изм. Лист № докум. Подпись Дата Лист 7 вводится специальный бит подтверждения, выставляемый на шину SDA после приёма 8 бит данных. 1.3.2 Подтверждение Таким образом, передача 8 бит данных от передатчика к приёмнику завершаются дополнительным циклом (формированием 9-го тактового импульса линии SCL), при котором приёмник выставляет низкий уровень сигнала на линии SDA, как признак успешного приёма байта. Подтверждение при передаче данных обязательно, кроме случаев окончания передачи ведомой стороной. Соответствующий импульс синхронизации генерируется ведущим. Передатчик отпускает (переводит в ВЫСОКОЕ состояние) линию SDA на время синхроимпульса подтверждения. Приёмник должен удерживать линию SDA в течение ВЫСОКОГО состояния синхроимпульса подтверждения в стабильном НИЗКОМ состоянии. В том случае, когда ведомый-приёмник не может подтвердить свой адрес (например, когда он выполняет в данный момент какие-либо функции реального времени), линия данных должна быть оставлена в ВЫСОКОМ состоянии. После этого ведущий может выдать состояние СТОП для прерывания пересылки данных. Если в пересылке участвует ведущий-приёмник, то он должен сообщить об окончании передачи ведомому-передатчику путём неподтверждения последнего байта. Ведомый-передатчик должен освободить линию данных для того, чтобы позволить ведущему выдать состояние СТОП или повторить состояние СТАРТ. 1.3.3 Синхронизация Синхронизация выполняется с использованием подключения к линии SCL по правилу монтажного И. Это означает, что ведущий не имеет монопольного права на управление переходом линии SCL из НИЗКОГО состояния в ВЫСОКОЕ. В том случае, когда ведомому необходимо дополнительное время на обработку принятого бита, он имеет возможность удерживать линию SCL в низком состоянии до момента готовности к приёму следующего бита. Таким образом, линия SCL будет находиться в НИЗКОМ состоянии на протяжении самого длинного НИЗКОГО периода синхросигналов. Устройства с более коротким НИЗКИМ периодом будут входить в состояние ожидания на время, пока не кончится длинный период. Когда у всех задействованных устройств кончится НИЗКИЙ период синхросигнала, линия SCL перейдет в ВЫСОКОЕ состояние. Все устройства начнут проходить ВЫСОКИЙ период своих синхросигналов. Первое устройство, у которого кончится этот период, снова установит линию SCL в НИЗКОЕ состояние. Таким образом, НИЗКИЙ период синхролинии SCL определяется наидлиннейшим периодом Разработка безопасного микропроцессорного устройства Изм. Лист № докум. Подпись Дата Лист 8 синхронизации из всех задействованных устройств, а ВЫСОКИЙ период определяется самым коротким периодом синхронизации устройств. Механизм синхронизации может быть использован приёмниками как средство управления пересылкой данных на байтовом и битовом уровнях. На уровне байта, если устройство может принимать байты данных с большой скоростью, но требует определенное время для сохранения принятого байта или подготовки к приёму следующего, то оно может удерживать линию SCL в НИЗКОМ состоянии после приёма и подтверждения байта, переводя таким образом передатчик в состояние ожидания. На уровне битов устройство, такое, как микроконтроллер без встроенных аппаратных цепей I²C или с ограниченными цепями, может замедлить частоту синхроимпульсов путём продления их НИЗКОГО периода. Таким образом скорость передачи любого ведущего адаптируется к скорости медленного устройства. 1.4 Адресация в шине I²C Каждое устройство, подключённое к шине, может быть программно адресовано по уникальному адресу. Для выбора приёмника сообщения ведущий использует уникальную адресную компоненту в формате посылки. При использовании однотипных устройств ИС часто имеют дополнительный селектор адреса, который может быть реализован как в виде дополнительных цифровых входов селектора адреса, так и в виде аналогового входа. При этом адреса таких однотипных устройств оказываются разнесены в адресном пространстве устройств, подключенных к шине. В обычном режиме используется 7-битная адресация. Процедура адресации на шине I²C заключается в том, что первый байт после сигнала СТАРТ определяет, какой ведомый адресуется ведущим для проведения цикла обмена. Исключение составляет адрес «Общего вызова», который адресует все устройства на шине. Когда используется этот адрес, все устройства в теории должны послать сигнал подтверждения. Однако устройства, которые могут обрабатывать «общий вызов», на практике встречаются редко. Первые семь битов первого байта образуют адрес ведомого. Восьмой, младший бит, определяет направление пересылки данных. «Ноль» означает, что ведущий будет записывать информацию в выбранного ведомого. «Единица» означает, что ведущий будет считывать информацию из ведомого. После того, как адрес послан, каждое устройство в системе сравнивает первые семь бит после сигнала СТАРТ со своим адресом. При совпадении устройство полагает себя выбранным как ведомый-приёмник или как ведомый-передатчик, в зависимости от бита направления. Адрес ведомого может состоять из фиксированной и программируемой части. Часто случается, что в системе будет несколько однотипных устройств (к примеру, Разработка безопасного микропроцессорного устройства Изм. Лист № докум. Подпись Дата Лист 9 ИМС памяти, или драйверов светодиодных индикаторов), поэтому при помощи программируемой части адреса становится возможным подключить к шине максимально возможное количество таких устройств. Количество программируемых битов в адресе зависит от количества свободных выводов микросхемы. Иногда используется один вывод с аналоговой установкой программируемого диапазона адресов. При этом в зависимости от потенциала на этом адресном выводе ИМС, возможно смещение адресного пространства драйвера так, чтобы однотипные ИМС не конфликтовали между собой на общей шине. Все специализированные ИМС, поддерживающие работу в стандарте шины I²C, имеют набор фиксированных адресов, перечень которых указан производителем в описаниях контроллеров. Комбинация бит 11110ХХ адреса зарезервирована для 10-битной адресации. Как следует из спецификации шины, допускаются как простые форматы обмена, так и комбинированные, когда в промежутке от состояния СТАРТ до состояния СТОП ведущий и ведомый могут выступать и как приёмник, и как передатчик данных. Комбинированные форматы могут быть использованы, например, для управления последовательной памятью. Во время первого байта данных можно передавать адрес в памяти, который записывается во внутренний регистр-защёлку. После повторения сигнала СТАРТа и адреса ведомого выдаются данные из памяти. Все решения об авто-инкременте или декременте адреса, к которому произошёл предыдущий доступ, принимаются конструктором конкретного устройства. Поэтому в любом случае лучший способ избежать неконтролируемой ситуации на шине перед использованием новой (или ранее не используемой) ИМС — следует тщательно изучить её описание (datasheet или reference manual), получив его с сайта производителя. Более того, производители часто размещают рядом более подробные инструкции по применению. В любом случае по спецификации шины все разрабатываемые устройства должны сбрасывать логику шины при получении сигнала СТАРТ или повторный СТАРТ и подготавливаться к приёму адреса. Тем не менее, основные проблемы с использованием I²C шины возникают именно из-за того, что разработчики, «начинающие» работать с I²C шиной, не учитывают того факта, что ведущий (часто — микропроцессор) не имеет монопольного права ни на одну из линий шины. Разработка безопасного микропроцессорного устройства Изм. Лист № докум. Подпись Дата Лист 10 1.5 Описание выводов ПЛИС и форматов данных Рисунок 3 – Описание выводов ПЛИС Таблица 1 – Описания портов порт CLK ширина 1 Режим in RESET_N 1 in ЕСА 1 in addr 7 in RW 1 in data_wr 8 in data_rd 8 out занятый 1 out Тип данных стандартная логика стандартная логика стандартная логика Интерфейс пользовательская логика пользовательская логика пользовательская логика стандартный логический вектор стандартная логика стандартный логический вектор стандартный логический вектор стандартная пользовательская логика Описание Системные часы. Асинхронный активный сброс низкого уровня. 0: транзакция не инициирована. 1: фиксирует в addr, rw и data_wr, чтобы инициировать транзакцию. Если ena имеет высокий уровень при завершении транзакции (то есть, когда занятость становится низкой), тогда для продолжения транзакции фиксируются новый адрес, команда чтения / записи и данные. Адрес целевого раба. пользовательская логика пользовательская логика 0: написать команду. 1: команда чтения. Данные для передачи, если rw = 0 (запись). пользовательская логика Данные получены, если rw = 1 (чтение). пользовательская 0: ведущее устройство Разработка безопасного микропроцессорного устройства Изм. Лист № докум. Подпись Дата Лист 11 логика логика ack_error 1 buffer стандартная логика пользовательская логика SDA 1 INOUT стандартная логика подчиненные устройства SCL 1 INOUT стандартная логика подчиненные устройства I2C находится в режиме ожидания, и данные последнего чтения доступны в data_rd. 1: команда зафиксирована и транзакция выполняется. 0: нет подтвержденных ошибок. 1: по крайней мере одна ошибка подтверждения произошла во время транзакции. ack_error очищается в начале каждой транзакции. Последовательная линия передачи данных шины I2C. Последовательная линия шины I2C. Рисунок 4 – Описание выводов ПЛИС Разработка безопасного микропроцессорного устройства Изм. Лист № докум. Подпись Дата Лист 12 2 VHDL-ОПИСАНИЕ МИКРОЭЛЕКТРОННОГО УСТРОЙСТВА Мастер I2C использует конечный автомат, показанный на рисунке 5, для реализации протокола шины I2C. После запуска компонент сразу переходит в состояние готовности . В этом состоянии он ожидает, пока сигнал ena не зафиксируется в команде. Начало состояние формирует условие запуска на шине I2C, а команда состояние передает адрес и Rw команды к шине. Затем состояние slv_ack1 захватывает и проверяет подтверждение ведомого. В зависимости от команды rw компонент затем переходит либо к записи данных в подчиненное устройство ( состояние wr ), либо к получению данных от подчиненного устройства ( состояние rd ). После завершения мастер захватывает и проверяет ответ ведомого (состояние slv_ack2 ) при записи или выдача собственного ответа ( состояние mstr_ack ) при чтении. Если сигнал ena фиксируется в другой команде, мастер немедленно продолжает другую запись ( состояние wr ) или чтение ( состояние rd ), если команда совпадает с предыдущей командой. Если он отличается от предыдущей команды (то есть чтения после записи или записи после чтения или нового адреса подчиненного устройства), то мастер выдает повторный запуск ( состояние запуска ) в соответствии со спецификацией I2C. Как только мастер завершает чтение или запись, и сигнал ena не фиксируется в новой команде, мастер генерирует условие останова (состояние останова ) и возвращается в готовое состояние. Разработка безопасного микропроцессорного устройства Изм. Лист № докум. Подпись Дата Лист 13 Рисунок 5 – Главный конечный автомат I2C Модуль Slave можно использовать через следующий интерфейс: Рисунок 6 – Интерфейс модуля Slave Разработка безопасного микропроцессорного устройства Изм. Лист № докум. Подпись Дата Лист 14 Когда значение read_req имеет высокое состояние, Slave извлекает данные data_to_master в одном и том же тактовом цикле, поэтому обязательно заранее установлены правильные данные. Когда data_valid становится в высокое состояние, data_from_master предоставляет данные в том же тактовом цикле. Slave игнорирует все главные команды, направленные на адреса, которые не совпадают с MINION_ADDR. 7 битов MINION_ADDR обычно задаются в формате старшего значащего бита (MSB) на стороне мастера. Например, 7-битный адрес «0000011» соответствует десятичному 3 на Slave, на самом деле это 6 на главном, потому что LSB никогда не отправляется. Разработка безопасного микропроцессорного устройства Изм. Лист № докум. Подпись Дата Лист 15 3 ТЕСТИРОВАНИЕ УСТРОЙСТВА РАБОТЫ МИКРОЭЛЕКТРОННОГО Для тестирования Master необходимо задать адрес Slave и подать на вход данных передаваемую информацию. Если Master свободен и Slave готов к приёму, начнётся передача данных. Рисунок 7 – Тестирование работы Master Для тестирования Slave необходимо задать адрес Master и подать на вход данных передаваемую информацию. Если шина данных SDA свободна, т.е. находится в высокоомном состоянии и Master готов к приёму, начнётся передача данных. Рисунок 8 – Тестирование работы Slave Для тестирования Master-Slave были промоделированы Master и Slave и написана программа на языке C которая продемонстрирована в приложении Д. Рисунок 9 – Тестирование Master-Slave Разработка безопасного микропроцессорного устройства Изм. Лист № докум. Подпись Дата Лист 16 4 АППАРАТНАЯ УСТРОЙСТВА РЕАЛИЗАЦИЯ МИКРОЭЛЕКТРОННОГО 4.1 Обоснование выбора ПЛИС и микросхемы конфигурационного ПЗУ Для реализации разработанного программного кода используем семейство ПЛИС Spartan-6. Семейство специально разработана для использования в электронных устройствах, рассчитанных на большие тиражи и невысокую стоимость. ПЛИС семейства Spartan-6 имеют емкость, достигающую 23 038 логических ячеек и 184 304 системных вентилей (триггеров). Иерархическая система элементов памяти выглядит следующим образом. Программа на ПЛИС семейства Spartan-6 может быть построена на базе шестивходовых таблиц преобразования (LUT-6 – Look-Up Table) конфигурируемых либо как 64-битное ОЗУ, либо как 64битный сдвиговый регистр; а также на встроенной блочной памяти, каждый блок конфигурируется как синхронное двухпортовое ОЗУ ёмкостью 4,824 кбит. Также, имеются быстрые интерфейсы PCI Express (1 примитив), GTP (8 примитивов) и блоки аппаратных умножителей DSP48 Slice (180 примитивов), а также блок управления и синтеза сигналов синхронизации (CMT). Основные особенности семейства Spartan-6: технологический процесс 45 нм; системная тактовая частота до 400 МГц; пониженное напряжение питания ядра – 1,2 В или 1,0 В; широкий диапазон напряжений блоков ввода-вывода – от 1,2 В до 3,3 В; программируемый ток выходных каскадов до 24 мА; поддержка 17 сигнальных стандартов ввода-вывода; 6 дифференциальных стандартов передачи сигналов, включая LVDS; скорость 1050 Мбит/с по каждой дифференциальной паре контактов; скорость 3,125 Гбит/с для приёмо-передатчиков; программируемый импеданс; контроллер памяти DDR, DDR2, DDR3, обеспечивающий полосу пропускания до 12,8 Гбит/с; блоки памяти емкостью 18 кбит, который можно сконфигурировать как два блока по 9 кбит. Предусмотрена защита проекта от копирования, используется шифрование конфигурационной последовательности по алгоритму AES. Для заданных целей была выбрана микросхема XC6SLX9-3FTG256. Скорость чипа (быстродействие логики) была выбрана максимально возможной для данного кристалла (-3). Для наших целей в соответствии с таблицей 3, в которой представлены рекомендуемые фирмой производителем микросхемы памяти, было выбрано Flash-ПЗУ S25FL008K с последовательным интерфейсом, которая также подходит для используемой ПЛИС XC6SLX9-3FTG256. В таблице 3 выделена строка с используемой микросхемой ПЛИС (XC6SLX9) и микросхемой Flash-ПЗУ (S25FL008K). Разработка безопасного микропроцессорного устройства Изм. Лист № докум. Подпись Дата Лист 17 Таблица 3 – Рекомендуемые типы Flash-ПЗУ Наименование ПЛИС Емкость, Мбит Flash-ПЗУ XC6SLX4 S25FL008K 2,7 XC6SLX9 S25FL008K 2,7 XC6SLX16 S25FL008K 3,7 XC6SLX25 S25FL008K 6,4 XC6SLX45 S25FL016K 11,9 XC6SLX75 S25FL032P 19,6 XC6SLX100 S25FL032P 26,5 XC6SLX150 S25FL064P 33,8 XC6SLX25T S25FL008K 6,4 XC6SLX45T S25FL016K 11,9 XC6SLX75T S25FL032P 19,6 XC6SLX100T S25FL032P 26,5 XC6SLX150T S25FL064P 33,8 4.2 Использованные ресурсы ПЛИС Проект успешно синтезирован и размещен на кристалле XC6SLX9-3FTG256. На рисунке 13 представлен отчет о синтезе, компиляции, разводке и расположении на кристалле проектируемого устройства. Рисунок 10 – Отчет о синтезе, компиляции, разводке и расположении на кристалле проектируемого устройства В результате, проект синтезировался и расположился на кристалле успешно (ошибки и предупреждения отсутствуют). На рисунках 14 и 15 представлена таблица используемых в ПЛИС ресурсов. Задействовано приблизительно 40-50% внутренней логики ПЛИС. Разработка безопасного микропроцессорного устройства Изм. Лист № докум. Подпись Дата Лист 18 Рисунок 11 – Таблица используемых в ПЛИС ресурсов (начало) Разработка безопасного микропроцессорного устройства Изм. Лист № докум. Подпись Дата Лист 19 Рисунок 12 – Таблица используемых в ПЛИС ресурсов (продолжение) На рисунке 16 представлено размещение устройства на кристалле ПЛИС XC6SLX9-3FTG256. Визульное размещение устройства на кристалле произведено с помощью встроенной в Xilinx ISE 14.5 утилиты «PlanAhead». Разработка безопасного микропроцессорного устройства Изм. Лист № докум. Подпись Дата Лист 20 Рисунок 13 – Размещение устройства на кристалле Разработка безопасного микропроцессорного устройства Изм. Лист № докум. Подпись Дата Лист 21 4.3 Оценка потребляемой устройством мощности Произведена оценка электрических параметров системы, а именно потребляемой устройством мощности, с помощью встроенной в Xilinx ISE 14.5 утилиты «XPower Analyzer». На рисунке 17 показана сводная таблица энергопотребления всего ПЛИС. Рисунок 14 – Таблица энергопотребления всего ПЛИС В соответствии с рисунком 17, максимальная допустимая температура окружающей среды для гарантированной работы ПЛИС составляет 84,3 °C, а рекомендумая темпаратура – 25,5 °C. Эффективная температура для теплоотвода составила 31,8 °C/Вт. Средняя мощность, потребляемая устройством, составляет 0,014 Вт, максимальная мощность – 0,023 Вт. Разработка безопасного микропроцессорного устройства Изм. Лист № докум. Подпись Дата Лист 22 Заключение В курсовой работе спроектировано специализированное микроэлектронное устройство, реализующее последовательную шину передачи данных I2C. Данное устройство может быть использовано как составная часть сложных систем обработки информации. Приведённые пояснения, блок-схемы алгоритмов и временные диаграммы призваны сделать технический продукт максимально понятным для любого специалиста, которому будет необходимо использовать кодер или его часть. ПЛИС, выбранная для реализации последовательной шины передачи данных I2C, является широкодоступной. Доступно также и программное обеспечение, позволяющее легко проверить и при необходимости скорректировать реализацию кодера. Поэтому не должно возникать никаких трудностей при использовании продукта. Разработка безопасного микропроцессорного устройства Изм. Лист № докум. Подпись Дата Лист 23 Список используемых источников 1 I2C [Электронный ресурс] / Материал из Википедии - свободной энциклопедии. 2013 Режим доступа: http://ru.wikipedia.org/wiki/I2C. 2 Сеть Фейстеля [Электронный ресурс] / Материал из Википедии свободной энциклопедии., 2019 Режим доступа: http://ru.wikipedia.org/wiki/Сеть_Фейстеля. 3 Шнайер Б. «Прикладная криптография», М.: Издательство Триумф, 2003 г. 4 Тарасов, И. Е. Разработка цифровых устройств на основе ПЛИС Xilinx с применением языка VHDL / И. Е. Тарасов. – М.: Горячая линия – Телеком, 2005. – 252 с. 5 Суворова, Е.А. Проектирование цифровых устройств на VHDL / Е. А. Суворова, Ю. Е. Шейнин. – СПб.: БХВ-Петербург, 2003 – 576 с. 6 Бочков К.А. Автоматика, телемеханика и связь на транспорте: Пособие по оформлению дипломных проектов / К.А.Бочков, С.Н.Харлап, Серенков А.Г., Кондрачук В.Ф. – Гомель: БелГУТ, 2002. – 70 с. Разработка безопасного микропроцессорного устройства Изм. Лист № докум. Подпись Дата Лист 24 Приложение А - Реализация Master на языке VHDL ----------------------------------------------------------------------------------- Company: -- Engineer: --- Create Date: 12:48:37 11/05/2019 -- Design Name: -- Module Name: i2c_master - logic -- Project Name: -- Target Devices: -- Tool versions: -- Description: --- Dependencies: --- Revision: -- Revision 0.01 - File Created -- Additional Comments: ----------------------------------------------------------------------------------library IEEE; USE ieee.std_logic_1164.all; USE ieee.std_logic_unsigned.all; -- Uncomment the following library declaration if using -- arithmetic functions with Signed or Unsigned values --use IEEE.NUMERIC_STD.ALL; -- Uncomment the following library declaration if instantiating -- any Xilinx primitives in this code. --library UNISIM; --use UNISIM.VComponents.all; entity i2c_master is GENERIC( input_clk : INTEGER := 50_000_000; --input clock speed from user logic in Hz bus_clk : INTEGER := 400_000); --speed the i2c bus (scl) will run at in Hz PORT( clk : IN STD_LOGIC; --system clock reset_n : IN STD_LOGIC; --active low reset ena : IN STD_LOGIC; --latch in command addr : IN STD_LOGIC_VECTOR(6 DOWNTO 0); --address of target slave rw : IN STD_LOGIC; --'0' is write, '1' is read data_wr : IN STD_LOGIC_VECTOR(7 DOWNTO 0); --data to write to slave busy : OUT STD_LOGIC; --indicates transaction in progress data_rd : OUT STD_LOGIC_VECTOR(7 DOWNTO 0); --data read from slave ack_error : BUFFER STD_LOGIC; --flag if improper acknowledge from slave sda : INOUT STD_LOGIC; --serial data output of i2c bus scl : INOUT STD_LOGIC); --serial clock output of i2c bus end i2c_master; architecture logic of i2c_master is CONSTANT divider : INTEGER := (input_clk/bus_clk)/4; --number of clocks in 1/4 cycle of scl TYPE machine IS(ready, start, command, slv_ack1, wr, rd, slv_ack2, mstr_ack, stop); --needed states SIGNAL state : machine; --state machine SIGNAL data_clk : STD_LOGIC; --data clock for sda SIGNAL data_clk_prev : STD_LOGIC; --data clock during previous system clock Разработка безопасного микропроцессорного устройства Изм. Лист № докум. Подпись Дата Лист 25 SIGNAL scl_clk : STD_LOGIC; --constantly running internal scl SIGNAL scl_ena : STD_LOGIC := '0'; --enables internal scl to output SIGNAL sda_int : STD_LOGIC := '1'; --internal sda SIGNAL sda_ena_n : STD_LOGIC; --enables internal sda to output SIGNAL addr_rw : STD_LOGIC_VECTOR(7 DOWNTO 0); --latched in address and read/write SIGNAL data_tx : STD_LOGIC_VECTOR(7 DOWNTO 0); --latched in data to write to slave SIGNAL data_rx : STD_LOGIC_VECTOR(7 DOWNTO 0); --data received from slave SIGNAL bit_cnt : INTEGER RANGE 0 TO 7 := 7; --tracks bit number in transaction SIGNAL stretch : STD_LOGIC := '0'; --identifies if slave is stretching scl begin --generate the timing for the bus clock (scl_clk) and the data clock (data_clk) PROCESS(clk, reset_n) VARIABLE count : INTEGER RANGE 0 TO divider*4; --timing for clock generation BEGIN IF(reset_n = '0') THEN --reset asserted stretch <= '0'; count := 0; ELSIF(clk'EVENT AND clk = '1') THEN data_clk_prev <= data_clk; --store previous value of data clock IF(count = divider*4-1) THEN --end of timing cycle count := 0; --reset timer ELSIF(stretch = '0') THEN --clock stretching from slave not detected count := count + 1; --continue clock generation timing END IF; CASE count IS WHEN 0 TO divider-1 => --first 1/4 cycle of clocking scl_clk <= '0'; data_clk <= '0'; WHEN divider TO divider*2-1 => --second 1/4 cycle of clocking scl_clk <= '0'; data_clk <= '1'; WHEN divider*2 TO divider*3-1 => --third 1/4 cycle of clocking scl_clk <= '1'; --release scl IF(scl = '0') THEN --detect if slave is stretching clock stretch <= '1'; ELSE stretch <= '0'; END IF; data_clk <= '1'; WHEN OTHERS => --last 1/4 cycle of clocking scl_clk <= '1'; data_clk <= '0'; END CASE; END IF; END PROCESS; --state machine and writing to sda during scl low (data_clk rising edge) PROCESS(clk, reset_n) BEGIN IF(reset_n = '0') THEN --reset asserted state <= ready; --return to initial state busy <= '1'; --indicate not available scl_ena <= '0'; --sets scl high impedance sda_int <= '1'; --sets sda high impedance ack_error <= '0'; --clear acknowledge error flag bit_cnt <= 7; --restarts data bit counter data_rd <= "00000000"; --clear data read port Разработка безопасного микропроцессорного устройства Изм. Лист № докум. Подпись Дата Лист 26 ELSIF(clk'EVENT AND clk = '1') THEN IF(data_clk = '1' AND data_clk_prev = '0') THEN --data clock rising edge CASE state IS WHEN ready => --idle state IF(ena = '1') THEN --transaction requested busy <= '1'; --flag busy addr_rw <= addr & rw; --collect requested slave address and command data_tx <= data_wr; --collect requested data to write state <= start; --go to start bit ELSE --remain idle busy <= '0'; --unflag busy state <= ready; --remain idle END IF; WHEN start => --start bit of transaction busy <= '1'; --resume busy if continuous mode sda_int <= addr_rw(bit_cnt); --set first address bit to bus state <= command; --go to command WHEN command => --address and command byte of transaction IF(bit_cnt = 0) THEN --command transmit finished sda_int <= '1'; --release sda for slave acknowledge bit_cnt <= 7; --reset bit counter for "byte" states state <= slv_ack1; --go to slave acknowledge (command) ELSE --next clock cycle of command state bit_cnt <= bit_cnt - 1; --keep track of transaction bits sda_int <= addr_rw(bit_cnt-1); --write address/command bit to bus state <= command; --continue with command END IF; WHEN slv_ack1 => --slave acknowledge bit (command) IF(addr_rw(0) = '0') THEN --write command sda_int <= data_tx(bit_cnt); --write first bit of data state <= wr; --go to write byte ELSE --read command sda_int <= '1'; --release sda from incoming data state <= rd; --go to read byte END IF; WHEN wr => --write byte of transaction busy <= '1'; --resume busy if continuous mode IF(bit_cnt = 0) THEN --write byte transmit finished sda_int <= '1'; --release sda for slave acknowledge bit_cnt <= 7; --reset bit counter for "byte" states state <= slv_ack2; --go to slave acknowledge (write) ELSE --next clock cycle of write state bit_cnt <= bit_cnt - 1; --keep track of transaction bits sda_int <= data_tx(bit_cnt-1); --write next bit to bus state <= wr; --continue writing END IF; WHEN rd => --read byte of transaction busy <= '1'; --resume busy if continuous mode IF(bit_cnt = 0) THEN --read byte receive finished IF(ena = '1' AND addr_rw = addr & rw) THEN --continuing with another read at same address sda_int <= '0'; --acknowledge the byte has been received ELSE --stopping or continuing with a write sda_int <= '1'; --send a no-acknowledge (before stop or repeated start) END IF; bit_cnt <= 7; --reset bit counter for "byte" states data_rd <= data_rx; --output received data state <= mstr_ack; --go to master acknowledge ELSE --next clock cycle of read state Разработка безопасного микропроцессорного устройства Изм. Лист № докум. Подпись Дата Лист 27 bit_cnt <= bit_cnt - 1; --keep track of transaction bits state <= rd; --continue reading END IF; WHEN slv_ack2 => --slave acknowledge bit (write) IF(ena = '1') THEN --continue transaction busy <= '0'; --continue is accepted addr_rw <= addr & rw; --collect requested slave address and command data_tx <= data_wr; --collect requested data to write IF(addr_rw = addr & rw) THEN --continue transaction with another write sda_int <= data_wr(bit_cnt); --write first bit of data state <= wr; --go to write byte ELSE --continue transaction with a read or new slave state <= start; --go to repeated start END IF; ELSE --complete transaction state <= stop; --go to stop bit END IF; WHEN mstr_ack => --master acknowledge bit after a read IF(ena = '1') THEN --continue transaction busy <= '0'; --continue is accepted and data received is available on bus addr_rw <= addr & rw; --collect requested slave address and command data_tx <= data_wr; --collect requested data to write IF(addr_rw = addr & rw) THEN --continue transaction with another read sda_int <= '1'; --release sda from incoming data state <= rd; --go to read byte ELSE --continue transaction with a write or new slave state <= start; --repeated start END IF; ELSE --complete transaction state <= stop; --go to stop bit END IF; WHEN stop => --stop bit of transaction busy <= '0'; --unflag busy state <= ready; --go to idle state END CASE; ELSIF(data_clk = '0' AND data_clk_prev = '1') THEN --data clock falling edge CASE state IS WHEN start => IF(scl_ena = '0') THEN --starting new transaction scl_ena <= '1'; --enable scl output ack_error <= '0'; --reset acknowledge error output END IF; WHEN slv_ack1 => --receiving slave acknowledge (command) IF(sda /= '0' OR ack_error = '1') THEN --no-acknowledge or previous no-acknowledge ack_error <= '1'; --set error output if no-acknowledge END IF; WHEN rd => --receiving slave data data_rx(bit_cnt) <= sda; --receive current slave data bit WHEN slv_ack2 => --receiving slave acknowledge (write) IF(sda /= '0' OR ack_error = '1') THEN --no-acknowledge or previous no-acknowledge ack_error <= '1'; --set error output if no-acknowledge END IF; WHEN stop => scl_ena <= '0'; --disable scl WHEN OTHERS => NULL; END CASE; END IF; Разработка безопасного микропроцессорного устройства Изм. Лист № докум. Подпись Дата Лист 28 END IF; END PROCESS; --set sda output WITH state SELECT sda_ena_n <= data_clk_prev WHEN start, --generate start condition NOT data_clk_prev WHEN stop, --generate stop condition sda_int WHEN OTHERS; --set to internal sda signal --set scl and sda outputs scl <= '0' WHEN (scl_ena = '1' AND scl_clk = '0') ELSE 'Z'; sda <= '0' WHEN sda_ena_n = '0' ELSE 'Z'; end logic; Разработка безопасного микропроцессорного устройства Изм. Лист № докум. Подпись Дата Лист 29 Приложение Б - Тестирование Master на языке VHDL -------------------------------------------------------------------------------- Company: -- Engineer: --- Create Date: 13:22:34 11/11/2019 -- Design Name: -- Module Name: F:/ISE/I2CMaster/Master_test_bench.vhd -- Project Name: I2CMaster -- Target Device: -- Tool versions: -- Description: --- VHDL Test Bench Created by ISE for module: i2c_master --- Dependencies: --- Revision: -- Revision 0.01 - File Created -- Additional Comments: --- Notes: -- This testbench has been automatically generated using types std_logic and -- std_logic_vector for the ports of the unit under test. Xilinx recommends -- that these types always be used for the top-level I/O of a design in order -- to guarantee that the testbench will bind correctly to the postimplementation -- simulation model. ------------------------------------------------------------------------------LIBRARY ieee; USE ieee.std_logic_1164.ALL; -- Uncomment the following library declaration if using -- arithmetic functions with Signed or Unsigned values --USE ieee.numeric_std.ALL; ENTITY Master_test_bench IS END Master_test_bench; ARCHITECTURE behavior OF Master_test_bench IS -- Component Declaration for the Unit Under Test (UUT) COMPONENT i2c_master PORT( clk : IN std_logic; reset_n : IN std_logic; ena : IN std_logic; addr : IN std_logic_vector(6 downto 0); rw : IN std_logic; data_wr : IN std_logic_vector(7 downto 0); busy : OUT std_logic; data_rd : OUT std_logic_vector(7 downto 0); ack_error : BUFFER std_logic; sda : INOUT std_logic; scl : INOUT std_logic ); END COMPONENT; Разработка безопасного микропроцессорного устройства Изм. Лист № докум. Подпись Дата Лист 30 --Inputs signal clk : std_logic := '0'; signal reset_n : std_logic := '0'; signal ena : std_logic := '0'; signal addr : std_logic_vector(6 downto 0) := (others => '0'); signal rw : std_logic := '0'; signal data_wr : std_logic_vector(7 downto 0) := (others => '0'); --BiDirs signal sda : std_logic; signal scl : std_logic; --Outputs signal busy : std_logic; signal data_rd : std_logic_vector(7 downto 0); signal ack_error : std_logic; -- Clock period definitions constant clk_period : time := 10 ns; BEGIN -- Instantiate the Unit Under Test (UUT) uut: i2c_master PORT MAP ( clk => clk, reset_n => reset_n, ena => ena, addr => addr, rw => rw, data_wr => data_wr, busy => busy, data_rd => data_rd, ack_error => ack_error, sda => sda, scl => scl ); -- Clock process definitions clk_process :process begin clk <= '0'; wait for clk_period/2; clk <= '1'; wait for clk_period/2; end process; -- Stimulus process stim_proc: process begin -- hold reset state for 100 ns. wait for 100 ns; addr <= "1010101"; data_wr <= "10011001"; ena <= '1'; reset_n <= '1'; rw <= '0'; wait for clk_period*10000; --wait for clk_period*2; Разработка безопасного микропроцессорного устройства Изм. Лист № докум. Подпись Дата Лист 31 --code wait; end process; END; Разработка безопасного микропроцессорного устройства Изм. Лист № докум. Подпись Дата Лист 32 Приложение B - Реализация Slave на языке VHDL library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; -----------------------------------------------------------entity I2C_minion is generic ( MINION_ADDR : std_logic_vector(6 downto 0); -- noisy SCL/SDA lines can confuse the minion -- use low-pass filter to smooth the signal -- (this might not be necessary!) USE_INPUT_DEBOUNCING : boolean := false; -- play with different number of wait cycles -- larger wait cycles increase the resource usage DEBOUNCING_WAIT_CYCLES : integer := 4); port ( scl : inout std_logic; sda : inout std_logic; clk : in std_logic; rst : in std_logic; -- User interface read_req : out std_logic; data_to_master : in std_logic_vector(7 downto 0); data_valid : out std_logic; data_from_master : out std_logic_vector(7 downto 0)); end entity I2C_minion; -----------------------------------------------------------architecture arch of I2C_minion is type state_t is (idle, get_address_and_cmd, answer_ack_start, write, read, read_ack_start, read_ack_got_rising, read_stop); -- I2C state management signal state_reg : state_t := idle; signal cmd_reg : std_logic := '0'; signal bits_processed_reg : integer range 0 to 8 := 0; signal continue_reg : std_logic := '0'; signal signal signal signal scl_reg sda_reg scl_debounced sda_debounced : : : : signal signal signal signal scl_pre_internal scl_internal sda_pre_internal sda_internal std_logic std_logic std_logic std_logic -- Helpers to figure out signal start_reg : signal stop_reg : signal scl_rising_reg : signal scl_falling_reg : : : : : := := := := std_logic std_logic std_logic std_logic 'Z'; 'Z'; 'Z'; 'Z'; := := := := next state std_logic := std_logic := std_logic := std_logic := 'Z'; '1'; 'Z'; '1'; '0'; '0'; '0'; '0'; -- Address and data received from master signal addr_reg : std_logic_vector(6 downto 0) := (others => '0'); signal data_reg : std_logic_vector(6 downto 0) := (others => '0'); signal data_from_master_reg : std_logic_vector(7 downto 0) := (others => '0'); Разработка безопасного микропроцессорного устройства Изм. Лист № докум. Подпись Дата Лист 33 signal scl_prev_reg -- Minion writes on signal scl_wen_reg signal scl_o_reg signal sda_prev_reg -- Minion writes on signal sda_wen_reg signal sda_o_reg : std_logic scl : std_logic : std_logic : std_logic sda : std_logic : std_logic := 'Z'; := '0'; := '0'; := 'Z'; -- unused for now := '0'; := '0'; -- User interface signal data_valid_reg : std_logic signal read_req_reg : std_logic signal data_to_master_reg : std_logic_vector(7 '0'); begin := '0'; := '0'; downto 0) := (others => debounce : if USE_INPUT_DEBOUNCING generate -- debounce SCL and SDA SCL_debounce : entity work.debounce generic map ( WAIT_CYCLES => DEBOUNCING_WAIT_CYCLES) port map ( clk => clk, signal_in => scl, signal_out => scl_debounced); -- it might not make sense to debounce SDA, since master -- and minion can both write to it... SDA_debounce : entity work.debounce generic map ( WAIT_CYCLES => DEBOUNCING_WAIT_CYCLES) port map ( clk => clk, signal_in => sda, signal_out => sda_debounced); scl_pre_internal <= scl_debounced; sda_pre_internal <= sda_debounced; end generate debounce; dont_debounce : if (not USE_INPUT_DEBOUNCING) generate process (clk) is begin if rising_edge(clk) then scl_pre_internal <= scl; sda_pre_internal <= sda; end if; end process; end generate dont_debounce; scl_internal <= '0' when scl_pre_internal = '0' else '1'; sda_internal <= '0' when sda_pre_internal = '0' else '1'; process (clk) is begin if rising_edge(clk) then -- Delay SCL and SDA by 1 clock cycle scl_prev_reg <= scl_internal; sda_prev_reg <= sda_internal; -- Detect rising and falling SCL Разработка безопасного микропроцессорного устройства Изм. Лист № докум. Подпись Дата Лист 34 scl_rising_reg <= '0'; if scl_prev_reg = '0' and scl_internal = '1' then scl_rising_reg <= '1'; end if; scl_falling_reg <= '0'; if scl_prev_reg = '1' and scl_internal = '0' then scl_falling_reg <= '1'; end if; -- Detect I2C START condition start_reg <= '0'; stop_reg <= '0'; if scl_internal = '1' and scl_prev_reg = '1' and sda_prev_reg = '1' and sda_internal = '0' then start_reg <= '1'; stop_reg <= '0'; end if; -- Detect I2C STOP condition if scl_prev_reg = '1' and scl_internal = '1' and sda_prev_reg = '0' and sda_internal = '1' then start_reg <= '0'; stop_reg <= '1'; end if; end if; end process; ----------------------------------------------------------- I2C state machine ---------------------------------------------------------process (clk) is begin if rising_edge(clk) then -- Default assignments sda_o_reg <= '0'; sda_wen_reg <= '0'; -- User interface data_valid_reg <= '0'; read_req_reg <= '0'; case state_reg is when idle => if start_reg = '1' then state_reg <= get_address_and_cmd; bits_processed_reg <= 0; end if; when get_address_and_cmd => if scl_rising_reg = '1' then if bits_processed_reg < 7 then bits_processed_reg <= bits_processed_reg + 1; addr_reg(6-bits_processed_reg) <= sda_internal; elsif bits_processed_reg = 7 then bits_processed_reg <= bits_processed_reg + 1; cmd_reg <= sda_internal; end if; end if; if bits_processed_reg = 8 and scl_falling_reg = '1' then bits_processed_reg <= 0; if addr_reg = MINION_ADDR then -- check req address Разработка безопасного микропроцессорного устройства Изм. Лист № докум. Подпись Дата Лист 35 state_reg <= answer_ack_start; if cmd_reg = '1' then -- issue read request read_req_reg <= '1'; data_to_master_reg <= data_to_master; end if; else assert false report ("I2C: target/minion address mismatch (data is being sent to another minion).") severity note; state_reg <= idle; end if; end if; ----------------------------------------------------- I2C acknowledge to master ---------------------------------------------------when answer_ack_start => sda_wen_reg <= '1'; sda_o_reg <= '0'; if scl_falling_reg = '1' then if cmd_reg = '0' then state_reg <= write; else state_reg <= read; end if; end if; ----------------------------------------------------- WRITE ---------------------------------------------------when write => if scl_rising_reg = '1' then bits_processed_reg <= bits_processed_reg + 1; if bits_processed_reg < 7 then data_reg(6-bits_processed_reg) <= sda_internal; else data_from_master_reg <= data_reg & sda_internal; data_valid_reg <= '1'; end if; end if; if scl_falling_reg = '1' and bits_processed_reg = 8 then state_reg <= answer_ack_start; bits_processed_reg <= 0; end if; ----------------------------------------------------- READ: send data to master ---------------------------------------------------when read => sda_wen_reg <= '1'; if data_to_master_reg(7-bits_processed_reg) = '0' then sda_o_reg <= '0'; else sda_o_reg <= 'Z'; end if; if scl_falling_reg = '1' then if bits_processed_reg < 7 then bits_processed_reg <= bits_processed_reg + 1; elsif bits_processed_reg = 7 then state_reg <= read_ack_start; Разработка безопасного микропроцессорного устройства Изм. Лист № докум. Подпись Дата Лист 36 bits_processed_reg <= 0; end if; end if; ----------------------------------------------------- I2C read master acknowledge ---------------------------------------------------when read_ack_start => if scl_rising_reg = '1' then state_reg <= read_ack_got_rising; if sda_internal = '1' then -- nack = stop read continue_reg <= '0'; else -- ack = continue read continue_reg <= '1'; read_req_reg <= '1'; -- request reg byte data_to_master_reg <= data_to_master; end if; end if; when read_ack_got_rising => if scl_falling_reg = '1' then if continue_reg = '1' then if cmd_reg = '0' then state_reg <= write; else state_reg <= read; end if; else state_reg <= read_stop; end if; end if; -- Wait for START or STOP to get out of this state when read_stop => null; -- Wait for START or STOP to get out of this state when others => assert false report ("I2C: error: ended in an impossible state.") severity error; state_reg <= idle; end case; --------------------------------------------------------- Reset counter and state on start/stop -------------------------------------------------------if start_reg = '1' then state_reg <= get_address_and_cmd; bits_processed_reg <= 0; end if; if stop_reg = '1' then state_reg <= idle; bits_processed_reg <= 0; end if; if rst = '1' then state_reg <= idle; end if; end if; end process; Разработка безопасного микропроцессорного устройства Изм. Лист № докум. Подпись Дата Лист 37 ----------------------------------------------------------- I2C interface ---------------------------------------------------------sda <= sda_o_reg when sda_wen_reg = '1' else 'Z'; scl <= scl_o_reg when scl_wen_reg = '1' else 'Z'; ----------------------------------------------------------- User interface ----------------------------------------------------------- Master writes data_valid <= data_valid_reg; data_from_master <= data_from_master_reg; -- Master reads read_req <= read_req_reg; end architecture arch; Разработка безопасного микропроцессорного устройства Изм. Лист № докум. Подпись Дата Лист 38 Приложение Г - Тестирование Slave на языке VHDL library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; use std.textio.all; use work.txt_util.all; -----------------------------------------------------------------------entity I2C_minion_TB_001_ideal is end I2C_minion_TB_001_ideal; -----------------------------------------------------------------------architecture Testbench of I2C_minion_TB_001_ideal is constant T : time := 20 ns; -- clk period constant TH_I2C : time := 100 ns; -- i2c clk quarter period(kbis) constant T_MUL : integer := 2; -- i2c clk quarter period(kbis) constant T_HALF : integer := (TH_I2C*T_MUL*2) / T; -- i2c halfclk period constant T_QUARTER : integer := (TH_I2C*T_MUL) / T; -- i2c quarterclk period signal signal signal signal signal signal '0'); signal signal signal '0'); signal signal '0'); signal '0'); clk rst scl sda : : : : std_logic std_logic std_logic std_logic := := := := '1'; '1'; 'Z'; 'Z'; state_dbg received_data : integer := 0; : std_logic_vector(7 downto 0) := (others => ack read_req data_to_master : std_logic := '0'; : std_logic := '0'; : std_logic_vector(7 downto 0) := (others => data_valid data_from_master : std_logic := '0'; : std_logic_vector(7 downto 0) := (others => data_from_master_reg : std_logic_vector(7 downto 0) := (others => shared variable seed1 : positive := 1000; shared variable seed2 : positive := 2000; -- simulation control shared variable ENDSIM : boolean := false; begin ---- Design Under Verification ----------------------------------------DUV : entity work.I2C_minion generic map ( MINION_ADDR => "0000011", USE_INPUT_DEBOUNCING => false) port map ( -- I2C scl => scl, sda => sda, -- default signals clk => clk, rst => rst, -- user interface read_req => read_req, data_to_master => data_to_master, data_valid => data_valid, data_from_master => data_from_master); Разработка безопасного микропроцессорного устройства Изм. Лист № докум. Подпись Дата Лист 39 ---- DUT clock running forever ---------------------------process begin if ENDSIM = false then clk <= '0'; wait for T/2; clk <= '1'; wait for T/2; else wait; end if; end process; ---- Reset asserted for T/2 -----------------------------rst <= '1', '0' after T/2; ----------------------------------------------------------- Save data received from the master in a register ---------------------------------------------------------process (clk) is begin if rising_edge(clk) then if data_valid = '1' then data_from_master_reg <= data_from_master; end if; end if; end process; ----- Test vector generation ------------------------------------------TESTS : process is -- half clock procedure i2c_wait_half_clock is begin for i in 0 to T_HALF loop wait until rising_edge(clk); end loop; end procedure i2c_wait_half_clock; -- quarter clock procedure i2c_wait_quarter_clock is begin for i in 0 to T_QUARTER loop wait until rising_edge(clk); end loop; end procedure i2c_wait_quarter_clock; -- Write Bit procedure i2c_send_bit ( constant a_bit : in std_logic) is begin scl <= '0'; if a_bit = '0' then sda <= '0'; else sda <= 'Z'; end if; i2c_wait_quarter_clock; scl <= 'Z'; i2c_wait_half_clock; scl <= '0'; i2c_wait_quarter_clock; Разработка безопасного микропроцессорного устройства Изм. Лист № докум. Подпись Дата Лист 40 end procedure i2c_send_bit; -- Read Bit procedure i2c_receive_bit ( variable a_bit : out std_logic) is begin scl <= '0'; sda <= 'Z'; i2c_wait_quarter_clock; scl <= 'Z'; i2c_wait_quarter_clock; if sda = '0' then a_bit := '0'; else a_bit := '1'; end if; i2c_wait_quarter_clock; scl <= '0'; i2c_wait_quarter_clock; end procedure i2c_receive_bit; -- Write Byte procedure i2c_send_byte ( constant a_byte : in std_logic_vector(7 downto 0)) is begin for i in 7 downto 0 loop i2c_send_bit(a_byte(i)); end loop; end procedure i2c_send_byte; -- Address procedure i2c_send_address ( constant address : in std_logic_vector(6 downto 0)) is begin for i in 6 downto 0 loop i2c_send_bit(address(i)); end loop; end procedure i2c_send_address; -- Read Byte procedure i2c_receive_byte ( signal a_byte : out std_logic_vector(7 downto 0)) is variable a_bit : std_logic; variable accu : std_logic_vector(7 downto 0) := (others => '0'); begin for i in 7 downto 0 loop i2c_receive_bit(a_bit); accu(i) := a_bit; end loop; a_byte <= accu; end procedure i2c_receive_byte; -- START procedure i2c_start is begin scl <= 'Z'; sda <= '0'; i2c_wait_half_clock; scl <= 'Z'; i2c_wait_quarter_clock; scl <= '0'; i2c_wait_quarter_clock; Разработка безопасного микропроцессорного устройства Изм. Лист № докум. Подпись Дата Лист 41 end procedure i2c_start; -- STOP procedure i2c_stop is begin scl <= '0'; sda <= '0'; i2c_wait_quarter_clock; scl <= 'Z'; i2c_wait_quarter_clock; sda <= 'Z'; i2c_wait_half_clock; i2c_wait_half_clock; end procedure i2c_stop; -- send write procedure i2c_set_write is begin i2c_send_bit('0'); end procedure i2c_set_write; -- send read procedure i2c_set_read is begin i2c_send_bit('1'); end procedure i2c_set_read; -- read ACK procedure i2c_read_ack (signal ack : out std_logic) is begin scl <= '0'; sda <= 'Z'; i2c_wait_quarter_clock; scl <= 'Z'; if sda = '0' then ack <= '1'; else ack <= '0'; assert false report "No ACK received: expected '0'" severity note; end if; i2c_wait_half_clock; scl <= '0'; i2c_wait_quarter_clock; end procedure i2c_read_ack; -- write NACK procedure i2c_write_nack is begin scl <= '0'; sda <= 'Z'; i2c_wait_quarter_clock; scl <= 'Z'; i2c_wait_half_clock; scl <= '0'; i2c_wait_quarter_clock; end procedure i2c_write_nack; -- write ACK procedure i2c_write_ack is begin scl <= '0'; sda <= '0'; i2c_wait_quarter_clock; Разработка безопасного микропроцессорного устройства Изм. Лист № докум. Подпись Дата Лист 42 scl <= 'Z'; i2c_wait_half_clock; scl <= '0'; i2c_wait_quarter_clock; end procedure i2c_write_ack; -- write to I2C bus procedure i2c_write ( constant address : in std_logic_vector(6 downto 0); constant data : in std_logic_vector(7 downto 0)) is begin state_dbg <= 0; i2c_start; state_dbg <= 1; i2c_send_address(address); state_dbg <= 2; i2c_set_write; state_dbg <= 3; -- dummy read ACK--don't care, because we are testing -- I2C minion i2c_read_ack(ack); if ack = '0' then state_dbg <= 6; i2c_stop; ack <= '0'; return; end if; state_dbg <= 4; i2c_send_byte(data); state_dbg <= 5; i2c_read_ack(ack); state_dbg <= 6; i2c_stop; end procedure i2c_write; -- write to I2C bus procedure i2c_quick_write ( constant address : in std_logic_vector(6 downto 0); constant data : in std_logic_vector(7 downto 0)) is begin state_dbg <= 0; i2c_start; state_dbg <= 1; i2c_send_address(address); state_dbg <= 2; i2c_set_write; state_dbg <= 3; -- dummy read ACK--don't care, because we are testing -- I2C minion i2c_read_ack(ack); if ack = '0' then state_dbg <= 6; i2c_stop; ack <= '0'; return; end if; state_dbg <= 4; i2c_send_byte(data); state_dbg <= 5; i2c_read_ack(ack); scl <= '0'; sda <= '0'; i2c_wait_quarter_clock; Разработка безопасного микропроцессорного устройства Изм. Лист № докум. Подпись Дата Лист 43 scl <= 'Z'; sda <= 'Z'; i2c_wait_quarter_clock; end procedure i2c_quick_write; -- read I2C bus procedure i2c_write_bytes ( constant address : in std_logic_vector(6 downto 0); constant nof_bytes : in integer range 0 to 1023) is variable data : std_logic_vector(7 downto 0) := (others => '0'); begin state_dbg <= 0; i2c_start; state_dbg <= 1; i2c_send_address(address); state_dbg <= 2; i2c_set_write; state_dbg <= 3; i2c_read_ack(ack); if ack = '0' then i2c_stop; return; end if; ack <= '0'; for i in 0 to nof_bytes-1 loop state_dbg <= 4; i2c_send_byte(std_logic_vector(to_unsigned(i, 8))); state_dbg <= 5; i2c_read_ack(ack); if ack = '0' then i2c_stop; return; end if; ack <= '0'; end loop; state_dbg <= 6; i2c_stop; end procedure i2c_write_bytes; -- read from I2C bus procedure i2c_read ( constant address : in std_logic_vector(6 downto 0); signal data : out std_logic_vector(7 downto 0)) is begin state_dbg <= 0; i2c_start; state_dbg <= 1; i2c_send_address(address); state_dbg <= 2; i2c_set_read; state_dbg <= 3; -- dummy read ACK--don't care, because we are testing -- I2C minion i2c_read_ack(ack); if ack = '0' then state_dbg <= 6; i2c_stop; return; end if; ack <= '0'; state_dbg <= 4; i2c_receive_byte(data); state_dbg <= 5; Разработка безопасного микропроцессорного устройства Изм. Лист № докум. Подпись Дата Лист 44 i2c_write_nack; state_dbg <= 6; i2c_stop; end procedure i2c_read; -- read from I2C bus procedure i2c_quick_read ( constant address : in std_logic_vector(6 downto 0); signal data : out std_logic_vector(7 downto 0)) is begin state_dbg <= 0; i2c_start; state_dbg <= 1; i2c_send_address(address); state_dbg <= 2; i2c_set_read; state_dbg <= 3; -- dummy read ACK--don't care, because we are testing -- I2C minion i2c_read_ack(ack); if ack = '0' then state_dbg <= 6; i2c_stop; return; end if; ack <= '0'; state_dbg <= 4; i2c_receive_byte(data); state_dbg <= 5; i2c_write_nack; scl <= '0'; sda <= '0'; i2c_wait_quarter_clock; scl <= 'Z'; sda <= 'Z'; i2c_wait_quarter_clock; end procedure i2c_quick_read; -- read I2C bus procedure i2c_read_bytes ( constant address : in std_logic_vector(6 constant nof_bytes : in integer range 0 to signal data : out std_logic_vector(7 begin state_dbg <= 0; i2c_start; state_dbg <= 1; i2c_send_address(address); state_dbg <= 2; i2c_set_read; state_dbg <= 3; i2c_read_ack(ack); if ack = '0' then state_dbg <= 6; i2c_stop; return; end if; for i in 0 to nof_bytes-1 loop -- dummy read ACK--don't care, because we -- I2C minion state_dbg <= 4; i2c_receive_byte(data); downto 0); 1023; downto 0)) is are testing Разработка безопасного микропроцессорного устройства Изм. Лист № докум. Подпись Дата Лист 45 state_dbg <= 5; if i < nof_bytes-1 then i2c_write_ack; else i2c_write_nack; end if; end loop; state_dbg <= 6; i2c_stop; end procedure i2c_read_bytes; begin print(""); print("------------------------------------------------------------"); print("----------------- I2C_minion_TB_001_ideal ------------------"); print("------------------------------------------------------------"); scl <= 'Z'; sda <= 'Z'; print("----------------- Testing a single write ------------------"); i2c_write("0000011", "11111111"); assert data_from_master_reg = "11111111" report "test: 0 not passed" severity warning; print("----------------- Testing a single write ------------------"); i2c_write("0000011", "11111010"); assert data_from_master_reg = "11111010" report "test: 0 not passed" severity warning; print("----------------- Testing repeated writes -----------------"); wait until rising_edge(clk); for i in 0 to 127 loop i2c_write("0000011", std_logic_vector(to_unsigned(i, 8))); assert i = to_integer(unsigned(data_from_master_reg)) report "writing test: " & integer'image(i) & " not passed" severity warning; end loop; print("----------------- Testing repeated reads ------------------"); for i in 0 to 127 loop data_to_master <= std_logic_vector(to_unsigned(i, 8)); i2c_read("0000011", received_data); assert i = to_integer(unsigned(received_data)) report "reading test: " & integer'image(i) & " not passed" & "test" severity warning; end loop; --------------------------------------------------------- Quick read/write -------------------------------------------------------print("----------------- Testing quick write --------------------"); i2c_quick_write("0000011", "10101010"); i2c_quick_write("0000011", "10101011"); i2c_quick_write("0000011", "10101111"); data_to_master <= std_logic_vector(to_unsigned(255, 8)); i2c_quick_read("0000011", received_data); state_dbg <= 6; i2c_stop; -------------------------------------------------------- Разработка безопасного микропроцессорного устройства Изм. Лист № докум. Подпись Дата Лист 46 -- Reads, writes from wrong minion addresses -- this should cause some assertion notes (needs manual -- confirmation) -------------------------------------------------------print("----------------- Testing wrong addresses -----------------"); print("-> The following 3 tests should all fail"); print("[0] ---------------"); i2c_write_bytes("1000011", 100); print("[1] ---------------"); i2c_read ("0101101", received_data); print("[2] ---------------"); i2c_read_bytes ("0000010", 300, received_data); wait until rising_edge(clk); ENDSIM := true; print("Simulation end..."); print(""); wait; end process; end Testbench; Разработка безопасного микропроцессорного устройства Изм. Лист № докум. Подпись Дата Лист 47 Приложение Г - Тестирование Master - Slave на языке C #include <Wire.h> void setup() { Wire.begin(); // join i2c bus (address optional for master) Serial.begin(9600); // start serial for output while (!Serial.dtr()) {} Serial.print("program begins"); Serial.println(); } void loop() { byte c; byte i; i = 0; while (true) { Wire.beginTransmission(3); Wire.write(i); Wire.endTransmission(); delay(1); Wire.requestFrom(3, 1); // request 6 bytes from slave device #2 while(!Wire.available()) {} c = Wire.read(); // receive a byte as character Serial.print("Write: "); Serial.print(i); // print the characterc Serial.print("; Read: "); Serial.print(c); // print the characterc Serial.println(); i = i + 1; if (i == 255) { Serial.print("Press any key to repeat"); Serial.println(); while (!Serial.available()) {} while (Serial.available()) Serial.read(); break; } delay(1); } } Разработка безопасного микропроцессорного устройства Изм. Лист № докум. Подпись Дата Лист 48