Уровень 49: Анатомия R-команды
Задание
Цель: собрать регистровый файл RV32I: банк 32×32 триггеров, дешифратор записи с замороженным x0 и два порта чтения. Именно эта схема стоит за каждой R-командой вида add x5, x6, x7. Это тот же RegFile, что вы видели в виджете 48-го, — теперь в железе.
Соберите регистровый файл RV32I — блок RegFile32: банк из 32 регистров по 32 бита, два порта чтения и одна запись по тактовому фронту. Именно эта схема стоит за каждой R-командой вида add x5, x6, x7: два исходных регистра идут на чтение, регистр назначения — на запись.
Проект многофайловый (вкладки слева), все три файла редактируемые:
regfile.v— главный файл: дешифратор записи изwe+waddrи инстанс банка.regbank.v— 32 регистра Reg32, дешифраторы адресов чтения и два 32:1 мьюкса.reg32.v— один 32-битный регистр с разрешением записи.
Интерфейс RegFile32: входы we (разрешение записи), waddr[4:0], wdata[31:0], raddr1[4:0], raddr2[4:0], clk; выходы rdata1[31:0], rdata2[31:0].
Три структурных требования проверяет схема:
- в
regfile.vдолжен быть инстансRegBank32с подключёнными всеми портами; - x0 заморожен: провод
wen[0]обязан собираться через константу1'b0— записывающего пути у x0 не существует; ram256иromиспользовать нельзя — только триггерыdffи вентиля.
Решение для самопроверки
Сначала попробуйте собрать блок сами. Решение ниже — порядок сборки и проверки.
Что должно получиться: RegFile32 проходит таблицу: запись в x5 читается по обоим портам, запись в x0 игнорируется, we=0 сохраняет значение — банк 32×32 с замороженным константой 1'b0 нулевым регистром.
Порядок сборки: снизу вверх. Reg32 → RegBank32 → RegFile32.
Шаг 1 — reg32.v: регистр с mux-обратной связью. Когда en=0, регистр должен сохранять значение. Идиома: на вход триггера подаётся d = (din & en) | (q & not(en)) — при выключенном разрешении регистр «читает сам себя». Сами биты — триггеры dff через generate for по 32 битам (приём уровня 37).
Шаг 2 — regbank.v: банк и два порта чтения. Инстанцируйте 32 экземпляра Reg32 — по одному на бит wen. Адреса чтения ra1/ra2 декодируйте в one-hot (те же и-цепочки, что и для записи), затем соберите по generate-мьюксу на порт: 32 вентиля AND на бит и or-дерево. Оба порта работают независимо: первый может читать x6, второй — x7 в один и тот же момент.
Шаг 3 — regfile.v: дешифратор записи и заморозка x0. Пять инверторов по битам waddr, и-цепочки на каждый wen[i], маска через we. Для wen[0] подключите константу 1'b0 — запись в x0 станет невозможна аппаратно. Порядок портов банка позиционный: RegBank32 bank(rdata1, rdata2, clk, wen, wdata, raddr1, raddr2).
Шаг 4 — проверка. Таблица уровня ортогональна: ни одна строка не читает регистр, записываемый в той же строке. Проверьте сами: запись в x5 и чтение по обоим портам; попытку записи в x0; одновременное чтение x5 и x31; we=0 — значение не меняется; перезапись x5 новым числом.
Принцип: запись происходит по фронту clk, а чтение — комбинационное. Поэтому два порта чтения не требуют ни второго такта, ни второго банка триггеров — только второго мьюкса.
Проверь себя
Почему два порта чтения не требуют второго такта?
Чтение комбинационное: адрес декодируется в one-hot, и мьюкс выбирает регистр сразу; запись происходит только по фронту clk. Второй порт — это просто второй мьюкс над тем же банком.