Уровень 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. Второй порт — это просто второй мьюкс над тем же банком.