mirror of
https://github.com/MPSU/APS.git
synced 2025-09-15 09:10:10 +00:00
ЛР2. Добавление информации по битовым сдвигам
This commit is contained in:
@@ -167,16 +167,46 @@ endmodule
|
||||
|
||||
---
|
||||
|
||||
При реализации АЛУ, вам также потребуется использовать [операции сдвига](https://ru.wikipedia.org/wiki/Битовый_сдвиг), к которым относятся:
|
||||
Реализуемое в данной лабораторной работе АЛУ использует операции битового сдвига. **Битовый сдвиг** — это операция, при которой все биты числа смещаются на заданное количество позиций. Сдвиг числа на _N_ бит эквивалентен _N_ сдвигам на 1 бит. В архитектуре RISC-V используются два типа сдвигов: **логический** и **арифметический**.
|
||||
|
||||
- `<<` — логический сдвиг влево
|
||||
- `>>` — логический сдвиг вправо
|
||||
- `>>>` — арифметический сдвиг вправо
|
||||
При **логическом сдвиге** биты сдвигаются влево или вправо, а освободившиеся позиции заполняются нулями. При этом разряды, "вытолкнутые" за пределы разрядной сетки числа, пропадают. Например, если выполнить логический сдвиг двоичного числа _1<u>0011010</u>_ на один бит влево, получится _<u>0011010</u>0_. Обратите внимание, что старшая единица была вытолкнута за границу и исчезла.
|
||||
|
||||

|
||||
|
||||
_Рисунок 3. Иллюстрация преобразования двоичного числа при логическом сдвиге._
|
||||
|
||||
При арифметическом сдвиге заполнение освобождённых битов выполняется так, чтобы сохранился знак числа. В дополнительном коде знак определяется старшим битом, поэтому:
|
||||
|
||||
- при **арифметическом сдвиге вправо** освободившиеся позиции заполняются значением старшего бита исходного числа. Это позволяет сохранить знак. Например, арифметический сдвиг на два бита вправо числа _<u>100110</u>10_ даёт _11<u>100110</u>_;
|
||||
- **арифметический сдвиг влево** эквивалентен логическому, так как заполнение младших битов нулями не влияет на знак числа.
|
||||
|
||||

|
||||
|
||||
_Рисунок 4. Иллюстрация преобразования двоичного числа при арифметическом сдвиге._
|
||||
|
||||
Битовый сдвиг имеет важный арифметический смысл — он соответствует умножению или делению числа на степень двойки:
|
||||
|
||||
- сдвиг влево на _N_ бит эквивалентен умножению на _2<sup>N</sup>_,
|
||||
- сдвиг вправо на _N_ бит эквивалентен целочисленному делению на _2<sup>N</sup>_.
|
||||
|
||||
Этот приём знаком должен быть знаком вам при работе с десятичной системой: умножая число на 10, мы просто дописываем справа ноль. То же самое работает и для деления: если отрезать последний разряд у числа 42, получится 4, что соответствует целочисленному делению на 10. В двоичной системе добавление (стирание) нуля справа эквивалентно умножению (делению) на 2.
|
||||
|
||||
Арифметический сдвиг важен тем, что сохраняет это свойство для знаковых чисел, представленных в дополнительном коде. Логический сдвиг вправо изменяет и знак, и модуль числа, поэтому не может использоваться для деления знаковых чисел.
|
||||
|
||||
Операции умножения и деления — это очень «дорогие» операции как с точки зрения элементов схемы (если эти операции реализуются аппаратно), так и с точки зрения времени их вычисления. Поэтому выполнение сдвигов в качестве замены умножения применяется повсеместно. Например, написав в коде языка C++ выражение `var * 8`, после компиляции вы наверняка получите операцию сдвига влево на 3.
|
||||
|
||||
Ещё одно применение сдвигов: установка и очищение флагов управляющих регистров. Дело в том, что обычно процессоры не имеют доступа к отдельным битам многоразрядных регистров — их значения читаются записываются целиком. Вот как можно реализовать битовые операции с помощью сдвигов:
|
||||
|
||||
```C++
|
||||
X = X | (1 << N); // Установка N-го бита
|
||||
X = X & ~(1 << N); // Очистка N-го бита
|
||||
Y = (X & (1 << N)) != 0; // Чтение N-го бита
|
||||
```
|
||||
|
||||
### Особенности реализации сдвига
|
||||
|
||||
> [!IMPORTANT]
|
||||
> Для **ВСЕХ** операций сдвига вы должны брать только 5 младших бит операнда B.
|
||||
> Для **ВСЕХ** операций сдвига в данной лабораторной работе вы должны брать только 5 младших бит операнда B.
|
||||
>
|
||||
> Сами посмотрите: выполнять операцию сдвига более чем на 31 для 32-битных чисел не имеет смысла, число полностью заполнится нулями (единицами). Т.е. сдвигая на любое число, большее 31, вы получите один и тот же результат. Для того чтобы закодировать 31 требуется минимум 5 бит, отсюда и это требование. Оно обязательно, поскольку старшие биты в дальнейшем будут использоваться по другому назначению и, если вы упустите это, ваш будущий процессор станет работать неправильно.
|
||||
|
||||
@@ -270,13 +300,13 @@ assign Result = $signed(A) / 10;
|
||||
|
||||
В этом примере некоторому сигналу `Result` присваивают результат деления **знакового** числа `A` на `10`.
|
||||
|
||||
Так как используются не все возможные комбинации управляющего сигнала АЛУ, то **при описании через `case` не забывайте использовать `default`**. Если описать АЛУ как задумано, то получится что-то похожее на _рис. 4_. Но не обязательно, зависит от вашего описания.
|
||||
Так как используются не все возможные комбинации управляющего сигнала АЛУ, то **при описании через `case` не забывайте использовать `default`**. Если описать АЛУ как задумано, то получится что-то похожее на _рис. 5_. Но не обязательно, зависит от вашего описания.
|
||||
|
||||

|
||||
|
||||
_Рисунок 3. Пример схемы, реализующей АЛУ._
|
||||
_Рисунок 5. Пример схемы, реализующей АЛУ._
|
||||
|
||||
Обратите внимание на то, что сумматор на _рис. 3_ отличается от всех остальных блоков. Для того, чтобы спроектированный в ЛР№1 32-разрядный сумматор был создан не зазря, а также для закрепления навыков по созданию экземпляров модулей внутри других модулей, вам предлагается использовать его при реализации АЛУ.
|
||||
Обратите внимание на то, что сумматор на _рис. 5_ отличается от всех остальных блоков. Для того, чтобы спроектированный в ЛР№1 32-разрядный сумматор был создан не зазря, а также для закрепления навыков по созданию экземпляров модулей внутри других модулей, вам предлагается использовать его при реализации АЛУ.
|
||||
|
||||
Другие блоки распознаны Vivado на основе представленных в описании АЛУ арифметических или логических выражений и в процессе синтеза будут реализованы через те компоненты ПЛИС, которые позволят лучше всего удовлетворить временным и физическим ограничениям проекта (см. главу "Этапы реализации проекта в ПЛИС"). Сумматор же будет реализован так, как это описали мы, поскольку вместо использования абстрактной операции "+" в описании АЛУ было сказано разместить конкретный модуль, реализующий конкретную схему. Такая реализация сумматора не является эффективной ни в плане временных характеристик, ни в плане количества затраченных на реализацию ресурсов ПЛИС. Но как уже упоминалось в ЛР№1, цель этой реализации — воспроизвести простоту логики рассуждений о том, как спроектировать сумматор.
|
||||
|
||||
|
Reference in New Issue
Block a user