mirror of
https://github.com/MPSU/APS.git
synced 2025-09-16 01:30:10 +00:00
Синхронизация с правками публикуемого издания (#101)
* СП. Обновление предисловия * СП. Обновление введения * СП. Обновление лаб * СП. Обновление доп материалов * СП. Введение * СП. Введение * СП. ЛР№4, 15 * СП. Базовые конструкции Verilog * Update Implementation steps.md * СП. ЛР 4,5,7,8,14 * СП. ЛР№8 * Синхронизация правок * СП. Финал * Исправление ссылки на рисунок * Обновление схемы * Синхронизация правок * Добавление белого фона .drawio-изображениям * ЛР2. Исправление нумерации рисунка
This commit is contained in:
committed by
GitHub
parent
d251574bbc
commit
9739429d6e
@@ -43,7 +43,7 @@ _Рисунок 1. Микроархитектура будущего проце
|
||||
- `mem_size_o` — размер данных при обращении в память;
|
||||
- `mem_we_o` — сигнал разрешения записи во внешнюю память;
|
||||
- `mem_wd_o` — данные для записи во внешнюю память;
|
||||
- `mem_rd_i` — считанные из внешней памяти данные;
|
||||
- `mem_rd_i` — считанные из внешней памяти данные.
|
||||
Эти сигналы используются при выполнении инструкций загрузки (сохранения) информации из (в) памяти данных.
|
||||
- еще у процессора появился вход `stall_i`, приостанавливающий обновление программного счётчика.
|
||||
|
||||
@@ -84,7 +84,7 @@ _Рисунок 1. Микроархитектура будущего проце
|
||||
|
||||
_Таблица 1. Описание портов декодера инструкций._
|
||||
|
||||
У данного модуля будет лишь один вход: `fetched_instr_i` — декодируемая в данный момент инструкция. Все остальные сигналы — это выходы модуля, которые можно классифицировать следующим образом:
|
||||
У данного модуля будет лишь один вход: `fetched_instr_i` — декодируемая в данный момент инструкция. Все остальные сигналы — это выходы модуля, которые можно сгруппировать по нескольким классам.
|
||||
|
||||
### Сигналы кода операции
|
||||
|
||||
@@ -105,7 +105,7 @@ _Таблица 1. Описание портов декодера инструк
|
||||
- `b_sel_o`,
|
||||
- `wb_sel_o`.
|
||||
|
||||
Сигналы `a_sel_o` и `b_sel_o` определяют откуда пойдут данные на операнды АЛУ `a_i`, `b_i` соответственно. К примеру, если мы хотим, чтобы оба операнда брались из регистрового файла, нам необходимо подать значение `0` на оба соответствующих мультиплексора.
|
||||
Сигналы `a_sel_o` и `b_sel_o` определяют откуда пойдут данные на операнды АЛУ `a_i`, `b_i` соответственно. К примеру, если мы хотим, чтобы оба операнда брались из регистрового файла, нам необходимо подать значение `0` на входы управляющих сигналов обоих мультиплексоров.
|
||||
|
||||
Сигнал `wb_sel_o` определяет источник данных для записи в регистровый файл: это либо результат операции на АЛУ, считанные данные из памяти данных, либо же данные, полученные из модуля регистров контроля и статуса.
|
||||
|
||||
@@ -149,7 +149,7 @@ _Таблица 2. Значения сигнала `mem_size_o` при пере
|
||||
|
||||
### Сигнал нелегальной инструкции
|
||||
|
||||
Это сигнал, который должен принять значение `1`, в случае если пришла инструкция, которая не входит в список поддерживаемых процессором.
|
||||
Сигнал, который должен принять значение `1`, в случае если пришла инструкция, которая не входит в список поддерживаемых процессором.
|
||||
|
||||
Это не единственное, что должен сделать декодер в подобной ситуации. Давайте разберем подробней, что должно происходить по приходу нелегальной инструкции.
|
||||
|
||||
@@ -162,7 +162,7 @@ _Таблица 2. Значения сигнала `mem_size_o` при пере
|
||||
- намеренная вставка неподдерживаемой инструкции (например для эксплуатации какой-нибудь уязвимости);
|
||||
- инструкция, которая на самом деле поддерживается процессором, но требует большего уровня привилегий и потому не может быть выполнена.
|
||||
|
||||
В случае появления инструкции, которая не поддерживается процессором, устройство управления должно обеспечить стабильность системы. В самом простом случае, такую инструкцию необходимо пропустить, сохранив так называемое **архитектурное состояние** процессора — т.е. сохранив значение всех элементов системы, характеризующих состояние системы в текущий момент. К таким элементам относятся: содержимое регистрового файла, основой памяти, содержимое регистров контроля и статуса и т.п. Значение программного счетчика также входит в архитектурное состояние процессора, однако в контексте пропуска инструкции с сохранением архитектурного состояния, его значение нужно изменить, иначе система оказалась бы в бесконечном цикле (неизменный счетчик бы указывал на ту же самую инструкцию, которая не должна менять архитектурного состояния).
|
||||
В случае появления инструкции, которая не поддерживается процессором, устройство управления должно обеспечить стабильность системы. В самом простом случае, такую инструкцию необходимо пропустить, сохранив так называемое **архитектурное состояние** процессора — т.е. сохранив значение всех элементов, характеризующих состояние системы в текущий момент. К таким элементам относятся: содержимое регистрового файла, основой памяти, содержимое регистров контроля и статуса и т.п. Значение программного счетчика также входит в архитектурное состояние процессора, однако в контексте пропуска инструкции с сохранением архитектурного состояния, его значение нужно изменить, иначе система оказалась бы в бесконечном цикле (неизменный счетчик бы указывал на ту же самую инструкцию, которая не должна менять архитектурного состояния).
|
||||
|
||||
Иными словами, в случае появления нелегальной инструкции, устройство управления (роль которого в нашей системе по большей части играет декодер) должно проследить за тем, чтобы в системе не изменилось ничего кроме программного счетчика. К сигналам, влияющим на изменение архитектурного состояния, относятся:
|
||||
|
||||
@@ -177,8 +177,6 @@ _Таблица 2. Значения сигнала `mem_size_o` при пере
|
||||
|
||||
то есть, должны быть запрещены все запросы на запись, обращения в память и любые "прыжки" программного счетчика.
|
||||
|
||||
|
||||
|
||||
Давайте теперь разберемся с тем, какие именно инструкции должен будет поддерживать наш процессор.
|
||||
|
||||
### Набор поддерживаемых инструкций **RISC-V** и способы их кодирования
|
||||
@@ -200,11 +198,11 @@ _Таблица 2. Значения сигнала `mem_size_o` при пере
|
||||
|
||||
В _Таблице 3_ приводится фрагмент из `спецификации RISC-V`. В верхней её части приводится 6 форматов кодирования инструкций: **R**, **I**, **S**, **B**, **U** и **J** (описание типов представлено в _таблице 4_). Затем список всех инструкций с конкретными значениями полей, соответствующих формату кодирования инструкции данного типа.
|
||||
|
||||
Под `rd` подразумевается 5-битный адрес регистра назначения (**r**egister **d**estination), `rs1` и `rs2` — 5-битные адреса регистров источников (**r**egister **s**ource), `imm` — непосредственный (immediate, задающийся прямиком в инструкции) операнд (константа), расположение и порядок битов которого указывается в квадратных скобках. Обратите внимание, что в разных форматах кодирования константы имеют различную разрядность, а их биты расположены по-разному. Для знаковых операций константу предварительно знаково расширяют до 32 бит. Для беззнаковых расширяют нулями до 32 бит.
|
||||
Под `rd` подразумевается 5-битный адрес регистра назначения (**r**egister **d**estination), `rs1` и `rs2` — 5-битные адреса регистров источников (**r**egister **s**ource), `imm` — непосредственный (immediate, задающийся прямиком в инструкции) операнд (константа), расположение и порядок битов которого указывается в квадратных скобках. Обратите внимание, что в разных форматах кодирования константы имеют различную разрядность, а их биты расположены по-разному. Непосредственные операнды всех типов интерпретируются как знаковые и требуют знакового расширения [[1](https://github.com/riscv/riscv-isa-manual/releases/download/20240411/unpriv-isa-asciidoc.pdf), стр. 23]. Исключение составляют 5-битные константы CSR-инструкций.
|
||||
|
||||

|
||||
|
||||
_Таблица 3. Базовый набор инструкций из спецификации RISC-V[[1, стр. 130]](https://github.com/riscv/riscv-isa-manual/releases/download/Ratified-IMAFDQC/riscv-spec-20191213.pdf), Стандартное расширение Zicsr[[1, стр. 131]](https://github.com/riscv/riscv-isa-manual/releases/download/Ratified-IMAFDQC/riscv-spec-20191213.pdf), а также привилегированная инструкция mret[[2, стр. 138]](https://github.com/riscv/riscv-isa-manual/releases/download/Priv-v1.12/riscv-privileged-20211203.pdf)._
|
||||
_Таблица 3. Базовый набор инструкций из спецификации RISC-V[[1, стр. 554]](https://github.com/riscv/riscv-isa-manual/releases/download/20240411/unpriv-isa-asciidoc.pdf), Стандартное расширение Zicsr[[1, стр.556]](https://github.com/riscv/riscv-isa-manual/releases/download/20240411/unpriv-isa-asciidoc.pdf), а также привилегированная инструкция mret[[2, стр.51]](https://github.com/riscv/riscv-isa-manual/releases/download/20240411/priv-isa-asciidoc.pdf)._
|
||||
|
||||
| Кодирование | Описание |
|
||||
|-------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
@@ -221,13 +219,13 @@ _Таблица 4. Описание типов форматов кодирова
|
||||
|
||||
Как уже описывалось в дополнительных материалах, декодирование инструкции начинается с поля `opcode` (**op**eration **code**, опкод). По этому полю определяется группа инструкций одного типа. Далее (для большинства типов кодирования) инструкция доопределяется через поля `func3` и `func7` (при наличии). Обратите внимание, что расположение этих полей одинаково для всех типов инструкций (см. верхнюю часть _таблицы 3_).
|
||||
|
||||
Поля `rs1`/`rs2`/`imm` и `rd` декодеру не нужны и используются напрямую для адресации в регистровом файле / использования непосредственного операнда в АЛУ.
|
||||
Поля `rs1`/`rs2`/`imm` и `rd` декодеру не нужны и используются напрямую для адресации регистров / задания констант.
|
||||
|
||||
Существуют особые инструкции, не имеющие никаких переменных полей (к примеру инструкция ECALL в _таблице 3_). Такие инструкции необходимо проверять целиком (нужно убедиться, что инструкция совпадает вплоть бита).
|
||||
|
||||
В _Таблице 5_ представлены все опкоды реализуемых нами инструкций. Представленные в ней коды операций 5-битные потому, что 2 младших бита полноценного 7-битного кода операции в реализуемых нами инструкциях должны всегда быть равны `11`. Если это не так, то вся инструкция уже запрещенная и не нуждается в дальнейшем декодировании.
|
||||
|
||||
Для удобства значения кодов операций определены в виде параметров в пакете `decoder_pkg`.
|
||||
Для удобства, значения кодов операций определены в виде параметров в пакете `decoder_pkg`.
|
||||
|
||||
|Параметр|Opcode| Описание группы операций | Краткая запись |
|
||||
|--------|------|-------------------------------------------------------------------------------------------------------|------------------------------------|
|
||||
@@ -241,7 +239,7 @@ _Таблица 4. Описание типов форматов кодирова
|
||||
|JALR |11001 |Записать в `rd` следующий адрес счетчика команд, в счетчик команд записать `rs1+imm` |`rd = PC + 4; PC = rs1+imm` |
|
||||
|AUIPC |00101 |Записать в `rd` результат сложения непосредственного операнда U-типа `imm_u` и счетчика команд |`rd = PC + (imm << 12)` |
|
||||
|MISC-MEM|00011 |Не производить операцию | `-` |
|
||||
|SYSTEM |11100 |Записать в `rd` значение `csr`. Обновить значение `csr` с помощью `rs1`. (либо `mret`/`ecall`/`ebreak`)|`csr = csr_op(rs1); rd = csr` |
|
||||
|SYSTEM |11100 |Записать в `rd` значение `csr`. Обновить значение `csr` с помощью `rs1`. (либо инструкция `mret`/`ecall`/`ebreak`)|`csr = csr_op(rs1); rd = csr` |
|
||||
|
||||
_Таблица 5. Описание кодов операций._
|
||||
|
||||
@@ -258,13 +256,13 @@ SYSTEM-инструкции используются для доступа к с
|
||||
|
||||
Кроме того, для возврата управления основному потоку инструкций, нужна дополнительная `SYSTEM`-инструкция привилегированного набора команд `MRET`.
|
||||
|
||||
Перечисленные выше инструкции являются "дополнительными" — их намеренно их добавили сверх стандартного набора инструкций, чтобы обеспечить требуемый нашей системе функционал. Однако осталось ещё две SYSTEM-инструкции, которые мы должны уметь декодировать, поскольку они есть в стандартном наборе инструкций.
|
||||
Перечисленные выше инструкции являются "дополнительными" — их добавили сверх стандартного набора инструкций, чтобы обеспечить требуемый нашей системе функционал. Однако осталось ещё две SYSTEM-инструкции, которые мы должны уметь декодировать, поскольку они есть в стандартном наборе инструкций.
|
||||
|
||||
Инструкции `ECALL` и `EBREAK` вызывают исключение. Подробнее исключения и прерывания будут разобраны в ЛР№10.
|
||||
|
||||
#### MISC-MEM инструкция
|
||||
#### MISC-MEM инструкции
|
||||
|
||||
В базовом наборе инструкций **RISC-V** к `MISC-MEM`-операции относится инструкция `FENCE`. В реализуемом процессорном ядре эта инструкция не должны приводить ни к каким изменениям. Инструкция `FENCE` в **RISC-V** необходима при работе с несколькими аппаратными потоками, или "хартами" (hart – «hardware thread»). В **RISC-V** используется расслабленная модель памяти (**relaxed memory model**): потоки «видят» все инструкции чтения и записи, которые исполняются другими потоками, однако видимый порядок этих инструкций может отличаться от реального. Инструкция `FENCE`, использованная между двумя инструкциями чтения и/или записи гарантирует, что остальные потоки увидят первую инструкцию перед второй. Реализация `FENCE` является опциональной в **RISC-V** и в данном случае в ней нет необходимости, так как в системе не предполагается наличия нескольких аппаратных потоков. Данная инструкция должна быть реализована как `NOP` (**n**o **op**eration).
|
||||
В базовом наборе инструкций **RISC-V** к `MISC-MEM`-операциям относятся инструкции `FENCE`, `FENCE.TSO`, `PAUSE` (которые объединены в таблице 5 в одну инструкцию `FENCE`). В реализуемом процессорном ядре эта инструкция не должна приводить к изменениям. Инструкция `FENCE` в **RISC-V** необходима при работе с несколькими аппаратными потоками, или "хартами" (hart – «hardware thread»). Она помогает согласовать доступ к данным между ними. В **RISC-V** используется "расслабленная модель" памяти (**relaxed memory model**): которая позволяет потокам видеть операции других потоков, но не обязательно в том порядке, в каком они были записаны в коде программы. Инструкция `FENCE`, использованная между двумя инструкциями чтения и/или записи гарантирует, что остальные потоки увидят первую инструкцию перед второй. Реализация `FENCE` является опциональной в **RISC-V** и в данном случае в ней нет необходимости, так как в системе не предполагается наличия нескольких аппаратных потоков. Данная инструкция должна быть реализована как `NOP` (**n**o **op**eration).
|
||||
|
||||
В _таблице 6_ представлены инструкции из таблицы 3 с приведением их типов, значениями полей `opcode`, `func3`, `func7`, функциональным описанием и примерами использования.
|
||||
|
||||
@@ -272,15 +270,17 @@ SYSTEM-инструкции используются для доступа к с
|
||||
|
||||
_Таблица 6. Расширенное описание инструкций RV32IZicsr._
|
||||
|
||||
Обратите внимание на операции `slli`, `srli` и `srai` (операции сдвига на константную величину). У этих инструкций немного измененный формат кодирования **I\***. Формат кодирования **I** предоставляет 12-битную константу. Сдвиг 32-битного числа более, чем на 31 не имеет смысла. Для кодирования числа 31 требуется всего 5 бит. Выходит, что из 12 бит константы используется только 5 бит для операции сдвига (в виде поля `shamt`, сокращение от **sh**ift **am**oun**t** — "сколько раз сдвигать"), а оставшиеся 7 бит – не используются. А, главное (какое совпадение!), эти 7 бит находятся ровно в том же месте, где у других инструкций находится поле `func7`. Поэтому, чтобы у инструкций `slli`, `srli` и `srai` использующих формат **I** не пропадала эта часть поля, к ней относятся как к полю `func7`.
|
||||
> [!IMPORTANT]
|
||||
> Обратите внимание на операции `slli`, `srli` и `srai` (операции сдвига на константную величину). У этих инструкций немного измененный формат кодирования **I\***. Формат кодирования **I** предоставляет 12-битную константу. Сдвиг 32-битного числа более, чем на 31 не имеет смысла. Для кодирования числа 31 требуется всего 5 бит. Выходит, что из 12 бит константы для операции сдвига используется только 5 бит (которые обозначены в виде поля `shamt`, сокращение от **sh**ift **am**oun**t** — "сколько раз сдвигать"), а оставшиеся 7 бит – не используются. А, главное (какое совпадение!), эти 7 бит находятся ровно в том же месте, где у других инструкций находится поле `func7`. Поэтому, чтобы у инструкций `slli`, `srli` и `srai` использующих формат **I** не пропадала эта часть поля, к ней относятся как к полю `func7`.
|
||||
|
||||
Также обратите внимание на инструкции `ecall`, `ebreak` и `mret`. Все эти инструкции I-типа имеют поле func3, равное нулю. С точки зрения декодирования инструкции I-типа, это одна и та же инструкция с разными значениями поля `imm`. Однако конкретно в данном случае (SYSTEM_OPCODE и `func3 == 0`) эти инструкции должны рассматриваться как совокупность всех 32-бит сразу (см. _таблицу 3_).
|
||||
> [!IMPORTANT]
|
||||
> Также обратите внимание на инструкции `ecall`, `ebreak` и `mret`. Все эти инструкции I-типа имеют поле func3, равное нулю. С точки зрения декодирования инструкции I-типа, это одна и та же инструкция с разными значениями поля `imm`. Однако конкретно в данном случае (SYSTEM_OPCODE и `func3 == 0`) эти инструкции должны рассматриваться как совокупность всех 32-бит сразу (см. _таблицу 3_).
|
||||
|
||||
### Формирование управляющих сигналов
|
||||
|
||||
Как говорилось ранее, декодер инструкций в процессоре служит для преобразования инструкции в набор управляющих сигналов, необходимых для ее исполнения. Таким образом, для каждой инструкции из _таблицы 3_ декодер должен поставить в соответствие конкретное значение для каждого из выходов, перечисленных в _таблице 1_.
|
||||
|
||||
Пример: для выполнения инструкции записи 32-бит данных из регистрового файла во внешнюю память `sw`, дешифратор должен направить в АЛУ два операнда (базовый адрес и смещение) вместе с кодом операции АЛУ (сложения) для вычисления адреса. Базовый адрес берется из регистрового файла, а смещение является непосредственным операндом инструкции S-типа. Таким образом для вычисления адреса записи декодер должен выставить следующие значения на выходах:
|
||||
Пример: для выполнения инструкции записи 32-бит данных из регистрового файла во внешнюю память (инструкции `sw`), дешифратор должен направить в АЛУ два операнда (базовый адрес и смещение) вместе с кодом операции АЛУ (сложения) для вычисления адреса записи. Базовый адрес берется из регистрового файла, а смещение является непосредственным операндом инструкции S-типа. Таким образом для вычисления адреса записи декодер должен выставить следующие значения на выходах:
|
||||
|
||||
- `a_sel_o = 2'd0`,
|
||||
- `b_sel_o = 3'd1`,
|
||||
@@ -336,15 +336,15 @@ _Таблица 7. Описание портов дешифратора кома
|
||||
|
||||
## Инструменты
|
||||
|
||||
В первую очередь язык описания аппаратуры **SystemVerilog** – это язык. С помощью этого языка человек объясняет либо синтезатору какое он хочет получить устройство, либо симулятору – как он хочет это устройство проверить. Синтезатор – это программа, которая создает из логических элементов цифровое устройство по описанию, предоставляемому человеком. Синтезатору внутри **Vivado** нужно объяснить, что от него нужно. Например, чтобы спросить дорогу у испанца, придется делать это на испанском языке, иначе он ничем не сможет помочь. А если вы знаете испанский, то скорее всего сможете это сделать еще и разными способами. В **SystemVerilog** точно также – одно и то же устройство можно описать разным кодом, но результат синтеза будет одним и тем же. Однако, часто два разных кода одинаковые по смыслу могут синтезироваться в разную аппаратуру, хотя функционально они будут идентичны, но могут отличаться, например, скоростью работы. Или одни и те же специальные языковые конструкции могут применяться для синтезирования разных цифровых элементов.
|
||||
**SystemVerilog** – это язык описания аппаратуры. С помощью этого языка человек объясняет либо синтезатору какое он хочет получить устройство, либо симулятору – как он хочет это устройство проверить. Синтезатор – это программа, которая создает из логических элементов цифровое устройство по описанию, предоставляемому человеком. Синтезатору внутри **Vivado** нужно объяснить, что от него нужно. Например, чтобы спросить дорогу у испанца, придется делать это на испанском языке, иначе он ничем не сможет помочь. А если вы хорошо знаете испанский, то скорее всего сможете это сделать еще и разными способами. В **SystemVerilog** точно также – одно и то же устройство можно описать разным кодом, но результат синтеза будет одним и тем же. Однако, часто два разных кода, одинаковые по смыслу, могут синтезироваться в разную аппаратуру, хотя функционально они будут идентичны, но могут отличаться, например, скоростью работы. Или одни и те же специальные языковые конструкции могут применяться для синтезирования разных цифровых элементов.
|
||||
|
||||
Декодер – комбинационная схема. Это значит, что каждый раз подавая на вход одни и те же значения, вы будете получать на выходе один и тот же результат, потому что комбинационные схемы не содержат элементов памяти.
|
||||
|
||||
Можно по-разному описывать комбинационные схемы. Например — через конструкцию `assign`. Для описания декодера отлично подойдет конструкция `case`, которая превратится не в мультиплексор, а в комбинационную схему с оптимальными параметрами критического пути. В доверилоговую эпоху разработчикам пришлось бы строить гигантские таблицы истинности и [карты Карно](https://ru.wikipedia.org/wiki/Карта_Карно), искать оптимальные схемы реализации. Сегодня эту задачу решает синтезатор, по описанию устройства сам находит наиболее эффективное решение.
|
||||
Можно по-разному описывать комбинационные схемы. Например — через конструкцию `assign`. Для описания декодера отлично подойдет конструкция `case`, которая превратится не в мультиплексор, а в комбинационную схему с оптимальными параметрами критического пути. В доверилоговую эпоху разработчикам пришлось бы строить гигантские таблицы истинности и [карты Карно](https://ru.wikipedia.org/wiki/Карта_Карно), искать оптимальные схемы реализации. Сегодня эту задачу решает синтезатор, по описанию устройства он сам находит наиболее эффективное решение.
|
||||
|
||||
Разница с реализацией мультиплексора в том, что в этом случае справа от знака равно всегда стоит константа. Получается это такой способ описать таблицу истинности. В такой код легко вносить правки и искать интересующие фрагменты.
|
||||
|
||||
Рассмотрим пример ниже. Внутри конструкции `always_comb`, перед конструкцией `case` указываются значения по умолчанию. Благодаря этому пропадает необходимость указывать все сигналы внутри каждого обработчика `case`, достаточно указать только те, что имеют значение отличное от значения по умолчанию. Представленный пример реализует комбинационную схему, которая при `control_signal== 4'b1100` будет выставлять сигнал `c == 1'b0`, то есть отличное, от значения по умолчанию. Сигнал `a` никак не меняется, поэтому он не указан в соответствующем обработчике. Если сигнал `size == 1'b0`, то `b` будет равен 1, а `d` равен 0. Если сигнал `size == 1'b1`, то наоборот – `b` будет равен 0, а `d` равен 1.
|
||||
Рассмотрим _листинг 1_. Внутри конструкции `always_comb`, перед конструкцией `case` указываются значения по умолчанию. Благодаря этому пропадает необходимость указывать все сигналы внутри каждого обработчика `case`, достаточно указать только те, что имеют значение отличное от значения по умолчанию. Представленный пример реализует комбинационную схему, которая при `control_signal== 4'b1100` будет выставлять сигнал `c == 1'b0`, то есть отличное, от значения по умолчанию. Сигнал `a` никак не меняется, поэтому он не указан в соответствующем обработчике. Если `sub_signal == 1'b0`, то `b` будет равен 1, а `d` равен 0. Если `sub_signal == 1'b1`, то наоборот – `b` будет равен 0, а `d` равен 1.
|
||||
|
||||
```Verilog
|
||||
module example (
|
||||
@@ -380,13 +380,15 @@ module example (
|
||||
endmodule
|
||||
```
|
||||
|
||||
Имейте в виду, что значения по умолчанию, описанные в начале блока `always_comb` можно использовать таким образом при помощи **блокирующих присваиваний** (которые следует использовать только в комбинационных блоках).
|
||||
_Листинг 1. Пример описания декодера._
|
||||
|
||||
Имейте в виду, что значения по умолчанию, описанные в начале блока `always_comb` можно использовать таким образом при помощи **блокирующих присваиваний** (которые [следует](../../Basic%20Verilog%20structures/Assignments.md) использовать только в комбинационных блоках).
|
||||
|
||||
Кроме того, использование вложенных блоков `case` обосновано только в ситуации создания блока декодера (т.е. в случаях, когда справа от всех присваиваний будут использованы константы, а не другие сигналы). В случае описания мультиплексора, вложенные блоки `case` могут быть синтезированы в каскад мультиплексоров, что негативно скажется на временных характеристиках схемы.
|
||||
|
||||
## Задание
|
||||
|
||||
Необходимо реализовать на языке **SystemVerilog** модуль декодера инструкций однотактного процессора RISC-V в соответствии с предложенной микроархитектурой. Далее приводится прототип разрабатываемого модуля.
|
||||
Необходимо реализовать на языке **SystemVerilog** модуль декодера инструкций однотактного процессора RISC-V в соответствии с предложенной микроархитектурой. В _листинге 2_ приводится прототип разрабатываемого модуля.
|
||||
|
||||
```Verilog
|
||||
module decoder (
|
||||
@@ -412,7 +414,9 @@ module decoder (
|
||||
endmodule
|
||||
```
|
||||
|
||||
В зависимости от стиля оформления, модуль может занимать больше сотни строк кода, но это не делает его реализацию сложной. По сути, дешифратор — это просто большой `case` с описанием того, в каком случае, какие сигналы и чему должны быть равны. Работа требует внимательности, немного усидчивости и понимания выполняемых действий. С огромной вероятностью в коде будут ошибки и их нужно будет исправлять. Ошибки — это нормально (не ошибается тот, кто ничего не делает), а исправление ошибок дает бесценный опыт разработки. Возможно, реализация этого модуля в какой-то момент покажется рутинной, но по окончании следующей лабораторной работы удовольствие от результата покажет, что оно того стоило.
|
||||
_Листинг 2. Прототип декодера инструкций._
|
||||
|
||||
В зависимости от стиля оформления, модуль может занимать больше сотни строк кода, но это не делает его реализацию сложной. По сути, декодер — это просто большой блок `case` с описанием того, в каком случае, какие сигналы и чему должны быть равны. Работа требует внимательности, немного усидчивости и понимания выполняемых действий. С огромной вероятностью в коде будут ошибки и их нужно будет исправлять. Ошибки — это нормально (не ошибается тот, кто ничего не делает), а исправление ошибок дает бесценный опыт разработки. Возможно, реализация этого модуля в какой-то момент покажется рутинной, но по окончании лабораторной работы №7 удовольствие от результата покажет, что оно того стоило.
|
||||
|
||||
## Порядок выполнения задания
|
||||
|
||||
|
Reference in New Issue
Block a user