-
Notifications
You must be signed in to change notification settings - Fork 32
Problem 01: Sign extension block
В этом задании мы научимся работать с шинами wire
, некоторыми новыми логическими операциями, вспомним как устроены отрицательные числа в машинной арифметике и сделаем блок расширения знака (в двух вариантах).
В этом руководстве и далее в курсе, а также вообще в языке Verilog принята следующая нотация: самый левый бит в записи N-разрядного двоичного числа — под номером N-1 — наиболее значащий (MSB — most significant bit), самый правый бит — под номером 0 — наименее значащий (LSB — least significant bit).
Число \ номер бита | 76543210 |
---|---|
5 | 00000101 |
11 | 00001011 |
43 | 00101011 |
В машинной арифметике отрицательные числа представляются дополнительным кодом (для примера взяты 12-битные числа):
Десятичное представление | Двоичное представление в дополнительном коде (12 бит) |
Двоичное представление противоположного числа в дополнительном коде (12 бит) |
---|---|---|
7 | 00000000111 | 11111111001 |
1 | 00000000001 | 11111111111 |
0 | 00000000000 | 00000000000 |
-1 | 11111111111 | 00000000001 |
-2 | 11111111110 | 00000000010 |
Можно заметить, что:
- Старший бит обозначает знак числа. Единица показывает, что число отрицательное.
- Число и противоположное ему связаны такой формулой:
-x = ~x + 1
(~
означает побитовую инверсию, как в языке C)
Теперь возьмем числа 7 и -7 и посмотрим на их представления как 16-битных чисел:
Десятичное представление | Двоичное представление в дополнительном коде |
Двоичное представление противоположного числа в дополнительном коде |
---|---|---|
7 | 000000000000111 | 111111111111001 |
Можно заметить, что:
- Для превращения положительного числа 12-битного числа в 16-битное нужно добавить 4 нуля.
- Для превращения отрицательного числа 12-битного числа в 16-битное нужно добавить 4 единицы.
Значит, расширять число нужно по-разному в зависимости от старшего бита. В нашем процессоре понадобится расширять 12-битные целые числа до 32-битных. В этом задании мы напишем соответствующий модуль.
Перейдите в каталог problems/01_sign_ext
в вашей локальной копии репозитория.
Откройте файл testbench.v
. Здесь созданы экземпляры 3 модулей:
- Экземпляр модуля расширения знака (первый вариант):
sign_ext se(.imm(imm), .ext_imm(ext_imm));
- Экземпляр модуля расширения знака (второй вариант):
sign_ext2 se2(.imm(imm), .ext_imm(ext_imm2));
- Экземпляр модуля смены знака целого 32-битного числа:
neg neg(.x(ext_imm), .minus_x(minus_ext_imm));
По заголовку модуля выясните, какая разрядность должна быть у выхода модуля расширения знака.
Объявите соответствующую шину в модуле testbench
.
Подсказка: Раньше мы пользовались только 1-разрядными шинами, и объявляли их вот так:
wire my_1bit_signal;
N-разрядная шина объявляется таким образом:
wire [N-1:0]my_signal; /* Замените N-1 на подходящее число */
Будьте внимательны, в нашем случае [N-1:0]
пишется слева от названия!
Чтобы проверить, что блок смены знака правильно работает, присвойте шине zero
значение суммы входа и выхода этого блока.
Подсказка: Устройство суммирования чисел не нужно проектировать каждый раз заново, как в лекции. Просто используйте +
.
В модуле neg
по формуле из начала лекции опишите логику превращения числа в противоположное.
В модуле sign_ext
опишите расширение знака для превращения 12-битного числа в 32-битное.
Указания:
- Старший бит 12-битной шины (11-ый) получают так:
wire msb = my_signal[11];
- Объединить 20-битную и 12-битную шину (именно в таком порядке) в 32-битную можно так:
wire [19:0]my_20_bit_signal;
wire [11:0]my_12_bit_signal;
wire [31:0]my_32_bit_signal = {my_20_bit_signal, my_12_bit_signal};
- Объединить 20 одинаковых шин:
wire [19:0]msb_x20 = {20{msb}};
В модуле sign_ext2
опишите схему расширения знака для превращения 12-битного числа в 32-битное с помощью тернарного оператора. Тернарный оператор op1 ? op2 : op3
имеет три операнда и принимает значение op2
, если op1 == 1
, иначе op3
.
Пример:
wire a;
wire d = а ? 0 : 1 /* Вместо 0 и 1 могут быть сигналы типа wire */;
Вопрос: Какая уже известная нам схема описана в примере?
Запустите симуляцию в Icarus Verilog, посмотрите сигналы в GTKWave. Проверьте, что модуль neg
действительно меняет знак, а sign_ext
и sign_ext2
правильно расширяют знак.
Чтобы GTKWave показывал десятичные числа со знаком, выделите желаемые сигналы в панели "Signals" и в меню выберите нужный формат "Edit -> Data Format -> Signed Decimal".
Итоговый результат должен выглядеть примерно следующим образом: