OVM/OVM методология/Основы объектно-ориентированного программирования
Содержание |
Разработка программного обеспечения, не связанная с физикой электричества и магнетизма, уже давно пытается создать многократно используемые, взаимозаменяемые, надежные компоненты. Важной моделью программирования, которая решает проблему, называется объектно-ориентированным программированием (ООП). Основная идея ООП заключается в том, что программы организуются как набор взаимодействующих объектов, каждый со своим собственным областью данных и функций. Объекты могут быть многократно использованы, потому что они инкапсулируют все, что им нужно для работы, могут быть построены с минимальным числом или без внешних зависимостей, и может быть высоко параметризованы. В этой главе вводятся основные понятия объектно-ориентированного программирования, в том числе понятия инкапсуляции и интерфейса. Глава завершается обсуждением того, почему ООП является важным для построения testbenches.
2.1 Процедурные против ООП
Чтобы понять ООП и его роль в проверке, необходимо сначала понять традиционное процедурное программирование и его ограничения. Это даст основу для понимания того, как ООП может преодолеть эти ограничения. В первые дни языка ассемблера, программисты и компьютерные архитекторы быстро обнаружили, что программы часто содержат последовательности инструкций, которые повторяются во всей программе. Повторение кода (в частности, с перфокарт) является трудоемким и порождает ошибки. Чтобы избежать трудоемкости и ошибок, вызванных повторением последовательностей, была изобретена подпрограмма. Подпрограмма является единицей повторно используемого кода. Вместо кодирования той же последовательности встроенных инструкций, вы вызываете подпрограмму. Параметры, передаваемые в подпрограмму, позволяют динамически изменять код. То есть, каждый вызов подпрограммы с различными значениями параметров заставляет подпрограмму вести себя по-разному в зависимости от конкретных значений параметров.
Каждый язык программирования любой значимости имеет конструкции для создания подпрограмм, процедур и функций, а также синтаксис для передачи в них параметров и возвращаемых значений. Эти функции могут использоваться для создания операций, которые часто используются. Тем не менее, некоторые операции очень распространены (таких как I / O, преобразования данных, численные методы и т. д.). И во избежание переписывания этих операций, программисты посчитали необходимым создать библиотеки часто используемых функций. В результате, большинство языков программирования включает такие библиотеки как часть пакета компилятора. Одним из наиболее известных примеров является библиотека C, которая поступает с каждым компилятором C. Она содержит полезные функции, такие как printf() (), COS (), atof (), и QSort (). Эти функции практически каждый программист будет использовать в тот или иной момент. Представьте себе, что писать собственные подпрограммы ввода / вывода или ваши собственные вычисления для преобразования чисел в строки и строк в числа. Был момент, когда программисты так и делали. Библиотеки универсальных функций все изменили и увеличили общую производительность программирования.
Как показывает практика программного обеспечения и передовых технологий, программисты начали думать на более высоком уровне абстракции, чем инструкции и процедуры. Вместо написания отдельных инструкций, программисты пишут код на языках, которые обеспечивают более высокую модель абстракции компьютера, и компиляторы или интерпретаторы переводят эти модели в конкретные инструкции. Библиотеки, такие как C библиотеки или STL в C + +, являются одной из форм абстракции. Они представляет собой набор функций, которые программисты могут использовать для создания все более сложных программы или абстракции. В своей основополагающей книге Алгоритмы + Структуры данных = Программы, Никлаус Вирт объясняет, что для решения любой задачи программирования, вы должны разработать абстракцию реальности, которая имеет характеристики и свойства задачи, и игнорировать остальные детали. Он утверждает, что набор данных, которые вам нужны для решения проблемы, формирует абстракцию. Поэтому, прежде чем вы сможете решить проблема, в первую очередь необходимо определить, какие данные нужно иметь, чтобы создать решение. Чтобы продолжить создание многократно используемой абстракции, мы должны создавать библиотеки данных объектов, которые могут быть многократно использованы для решения конкретных видов проблем. Поиск способа сделать это приводит к развитию объектно-ориентированных технологий.
Объектно-ориентированный анализ и проектирование программ сосредоточен вокруг данных объектов, функциональности, связанной с каждым объектом, и отношения между объектами.
Объектно-ориентированные языки предоставляют средства для отделения проблем программы, и выделения каждой из них независимо друг от друга, и для инкапсуляции данных абстракций и представление их через строго определенные интерфейсы. Полностью объектно-ориентированная программа строится путем разделения функциональности программы в различные классы, определения интерфейса для каждого класса, а затем установления связей и взаимодействий между компонентами через их интерфейсы.
2.2 Классы и объекты
Основным модулем программирования на объектно-ориентированных языках, таких как SystemVerilog, является класс. Класс содержит элементы данных, называемые членами, и задач и функций, называемых методами. Для выполнения объектно-ориентированных программ, вы должны создать один или более классов в основной программе, а затем вызвать методы на различных объектах. Хотя термины класс и объект иногда используются как синонимы, как правило, термин класс относится к классу декларации объекта, а термин объект относится к экземпляру класса. Чтобы проиллюстрировать эти понятия, ниже приведен пример простой класс register.
Это очень простой класс с одной переменной, и двумя методами, read() и write(). Чтобы использовать этот класс, вы создаете объекты путем создания экземпляра класса, а затем вызвать методы объекта, как показано ниже
Локальный атрибут contents класса указывает компилятору строго соблюдать границы класса. Если вы пытаетесь получить доступ к contents напрямую, компилятор выдаст ошибку. Вы можете получить доступ к содержимому через доступные функции чтения и записи. Этот вид контроля доступа важен для гарантирования независимости от внутренностей класса и тем самым делает класс многократно используемым. Вы можете использовать классы для создания новых типов данных, таких, как наш простой register. Использование классов для создания новых типов данных является важной частью ООП. Вы можете также использовать их для инкапсуляции математических вычислений или создания динамических структур данных, таких как стеки, списки, очереди, и так далее. Инкапсуляция организации структур данных или сведений о вычислениях в классе делает структуру данных или вычислений многократно используемыми. В качестве более полного примера, давайте посмотрим на полезный тип данных, стек. Стек - это LIFO ("последним пришёл - первым обслужен") структура. Элементы помещаются в стек командой push(), а извлекаются из стека pop(). Pop () возвращает последний элемент, помещенный в стек, и удаляет его из структуры данных. Внутренние элемент stkptr следит за вершиной стека. Элемент, на который он указывает, это вершина стека, а все, что ниже его (то есть, с меньшим индексом) ниже в стеке. Ниже приведена базовая реализация стека в SystemVerilog
Класс stack инкапсулирует все, что нужно знать о стеке данных структуры. Он содержит интерфейс и реализацию интерфейса. Интерфейс – это набор методов, которые используются для взаимодействия с классом. Реализация - это код, который заставляет класс работать. Интерфейс нашего стека содержит следующие методы:
Не существует другого способа взаимодействия со стеком, как с помощью этих методов. Есть также два элемента данных класса, stk и stkptr, которые представляют фактическую структуру стека. Тем не менее, эти два элемента локальные, что означает, что компилятор запретит любые попытки доступа к ним за пределами класса. Для предотвращения доступа к внутренней структуре данных извне, мы можем сделать некоторые гарантии о состоянии данных. Например, Push () и Pop () могут рассчитывать на то, что stkptr корректно и указывает на вершину стека. Если бы можно было изменить значение stkptr иными средствами, чем с помощью интерфейса функций, тогда Push () и Pop () пришлось бы прибегнуть к дополнительным затратам и возможностям для ненадежной проверки истинности stkptr. Реализация интерфейса встроенная. Объявление класса содержит не только определение интерфейса, а также реализацию каждой функции интерфейса. Оба C + + и SystemVerilog позволяют отделить реализацию от интерфейса. Разделение интерфейса и реализации является важной концепцией. Программисты, пишущие на C + +, могут использовать файлы заголовков для ввода интерфейс и. куб (или. срр или любой другой компилятор использует) для реализации.
Есть некоторые важные явления доступа через класс интерфейсов. Одним из них является возможность многократного использования. Мы можем удобно использовать классы, интерфейсы которых четко определены и хорошо объяснены, чем те, чьи интерфейсы нечеткие. Другим важным явлением обеспечения доступа через класс интерфейсов является надежность. Авторы класса может гарантировать определенную инвариантность (например, stkptr меньше, чем размер имеющегося массива STK) когда они знают, что пользователи не будут изменять данные иначе, чем предоставляемыми средствами. Кроме того, пользователи могут ожидать, что состояние объекта будет предсказуемым, когда они придерживаются интерфейса. Ясность другое явление. Интерфейс может описать всю семантику класса. Объект не будет делать ничего другого, чем выполнять операции, доступные через интерфейс. Это делает проще понять для тех, кто использует класс, что именно он будет делать.