Уровень 51: Константа внутри команды
Задание
Цель: собрать sign-extend: imm[11:0] разворачивается до 32 бит копией знакового бита. Это сердце I-формата addi — константа живёт внутри самой команды. Восемь готовых I-модулей (slti32.v…srai32.v) лежат в проекте только для чтения — они появятся в вашем ядре позже; вкладка «Ассемблер» уже собирает слова.
Не все команды берут оба операнда из регистров. Команда addi x1, x0, -1 складывает x0 с числом, записанным прямо в машинном слове. Такое число называется непосредственным операндом — immediate. В команде оно занимает 12 бит, а АЛУ работает с 32-битными числами. Ваша задача — блок SignExt32: расширить immediate до 32 бит с сохранением знака.
Проект многофайловый:
signext.v— редактируемый: интерфейсimm[11:0]→ext[31:0]. Ваша работа.slti32.v…srai32.v— восемь готовых I-модулей, только для чтения. Это будущие исполнители I-команд вашего ядра; пока их нужно просто видеть — к каким модулям относится каждый код операции.
Схема проверяет sign-extend на границах 12-битного диапазона: 0, 1, 0x3FF/0x400 (граница старших бит), 0x7FF (2047), 0x800 (−2048), 0xFFF (−1) и другие.
Вторая половина уровня — вкладка «Ассемблер», которая на этом уровне уже работает: она превращает мнемонику в машинное слово и обратно. Соберите в ней addi x1, x0, -1 и найдите в полученном слове FFF00093 поля I-формата: imm[11:0] в старших битах, rs1, funct3, rd и opcode ниже.
Решение для самопроверки
Сначала реализуйте SignExt32 сами. Решение ниже поможет свериться.
Что должно получиться: SignExt32 верен на границах диапазона: 0x7FF → 2047, 0x800 → −2048, 0xFFF → −1 (старшие 20 бит — единицы); ассемблер собирает addi x1, x0, -1 в слово FFF00093.
Шаг 1 — разберите 12-битное число. Старший бит — бит 11. В дополнительном коде он определяет знак: у 0x7FF (2047) он ноль, у 0x800 (−2048) — единица.
Шаг 2 — соберите схему из буферов. Младшие 12 бит ext — прямые копии imm[0..11]. Старшие 20 бит — все подключены к imm[11]: знаковый бит тиражируется. Копия бита — буфер or(out, in, 1'b0), идиома уровня 50. Всего 32 провода-копии, ни одного триггера: sign-extend — чисто комбинационный блок.
Шаг 3 — проверьте границы. Таблица уровня содержит все крайние случаи. Сверьте два самых показательных: 0x7FF → 2047 (старшие биты — нули), 0xFFF → 0xFFFFFFFF, то есть −1 (старшие биты — единицы).
Шаг 4 — сверьте ассемблер. addi x1, x0, -1: imm = FFF, rs1 = x0 = 00000, funct3 = 000, rd = x1 = 00001, opcode OP-IMM = 0010011. Сложите поля — получится FFF00093. Если забыть sign-extend, константа −1 превратится в 4095: предсказание уровня предлагает выбрать между −1, 2047 и 4095, и именно 4095 получается, когда старшие 20 бит остаются нулями.
Принцип: immediate — не отдельный регистр, а часть самой команды. Процессор извлекает его из инструкции и расширяет до нужной разрядности прямо в тракте данных.
Проверь себя
Что случится с константой −1 без sign-extend?
Старшие 20 бит останутся нулями, и −1 превратится в 4095. Знаковый бит тиражируется в старшие позиции именно для того, чтобы значение сохранилось: 12 бит честно становятся 32.