Skip to content

Problem 01: Sign extension block

Viktor Prutyanov edited this page Feb 12, 2019 · 6 revisions

Блок расширения знака

В этом задании мы научимся работать с шинами 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 модулей:

  1. Экземпляр модуля расширения знака (первый вариант):
sign_ext se(.imm(imm), .ext_imm(ext_imm));
  1. Экземпляр модуля расширения знака (второй вариант):
sign_ext2 se2(.imm(imm), .ext_imm(ext_imm2));
  1. Экземпляр модуля смены знака целого 32-битного числа:
neg neg(.x(ext_imm), .minus_x(minus_ext_imm));

Задача №1

По заголовку модуля выясните, какая разрядность должна быть у выхода модуля расширения знака. Объявите соответствующую шину в модуле testbench.

Подсказка: Раньше мы пользовались только 1-разрядными шинами, и объявляли их вот так:

wire my_1bit_signal;

N-разрядная шина объявляется таким образом:

wire [N-1:0]my_signal; /* Замените N-1 на подходящее число */

Будьте внимательны, в нашем случае [N-1:0] пишется слева от названия!

Задача №2

Чтобы проверить, что блок смены знака правильно работает, присвойте шине zero значение суммы входа и выхода этого блока.

Подсказка: Устройство суммирования чисел не нужно проектировать каждый раз заново, как в лекции. Просто используйте +.

Задача №3

В модуле neg по формуле из начала лекции опишите логику превращения числа в противоположное.

Задача №4

В модуле 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}};

Задача №5

В модуле sign_ext2 опишите схему расширения знака для превращения 12-битного числа в 32-битное с помощью тернарного оператора. Тернарный оператор op1 ? op2 : op3 имеет три операнда и принимает значение op2, если op1 == 1, иначе op3.

Пример:

wire a;
wire d = а ? 0 : 1 /* Вместо 0 и 1 могут быть сигналы типа wire */;

Вопрос: Какая уже известная нам схема описана в примере?

Задача №6

Запустите симуляцию в Icarus Verilog, посмотрите сигналы в GTKWave. Проверьте, что модуль neg действительно меняет знак, а sign_ext и sign_ext2 правильно расширяют знак.

Чтобы GTKWave показывал десятичные числа со знаком, выделите желаемые сигналы в панели "Signals" и в меню выберите нужный формат "Edit -> Data Format -> Signed Decimal".

Итоговый результат должен выглядеть примерно следующим образом: