Tags: risc-v

worklog: побайтовый доступ к 32-битной памяти

А как, собсно, это работает? У чипов SDRAM, насколько мне известно, нет возможности записывать только часть битов*. У некоторых широких SRAM, наоборот, есть (например, 16-битная шина и два отдельных строба, типа BH и BL). Как же это сделать? Считать полностью слово, заменить байт, записать обратно? Bus turn-around - это же ммммммееееддленнно

* Или я всё понял неправильно и "data masking" (сигналы типа DQML/DQMH в терминологии Micron) это оно и есть?

[подумав] Да, похоже на то, что я недоглядел - сигналы DQM в самом деле нужны для этого (но не только). При записи они управляют блокировкой, собсно, записи - если строб установлен в 1, запись в указанном канале НЕ осуществляется. Нушож, это хорошо.

Значит, внешняя шина будет из 32 бит данных, 32 бит адреса, стробов rd/wr и индикатора размера данных (байт/полуслово/слово). И где-то там, уже снаружи процессора, будет хитрый контроллер SDRAM... который уже придётся делать на ПЛИС, наверное. Но, мобыть, и нет.

worklog: заказал платы регистров

Пять плат всего, но сборку заказал только двух, ибо недешёвое удовольствие - сама сборка как бы бесплатная, но детальки-то производство всё равно закупает и в итоге 128 недорогих микросхем (32 регистра по 4 микросхемы в каждом) превращается почти в сотню баксов на каждую из собранных плат.

И вроде как жаба душит, но собирать эти платы вручную я точно не хочу :)

worklog: двоичный компаратор - работает!

Это просто великолепно, несмотря даже на то, что в плате оснастки дефект (то ли металлизации в переходнике нет, то ли одно из двух -- нет контакта в одном сигнале; решил пробросом навесного проводка прям внутрь платы компаратора). Всё равно этот блок буду переделывать, чтобы добавить проверку платы CSR, заодно и закажу в более надёжном месте*.

Операции EQ, NEQ, LT, GE, ULE, UGE (равно, не равно, меньше, больше или равно, беззнаковое меньше, беззнаковое больше или равно; всё это нужно для условных переходов) фунциклируют как надо; флаги TRUE/FALSE выдаются; константы для инструкций SLT/SLTU формируется.

Вообще сравнение можно было бы сделать и на арифметике, но я решил, что так будет проще - два разных отдельных блока могут работать одновременно, например, чтобы вычислять условные переходы: компаратор сравнивает регистры, а арифметика в этот момент вычисляет предполагаемый адрес. Если сравнение не сработало, вычисленное значение просто отбрасывается, а если сработало - загружается в Program Counter. Поэтому отдельный флажок COND_TRUE очень даже нужен и полезен.

Отступать некуда - надо собирать АЛУ, а потом ещё блок регистров общего назначения; затем дешифратор команд (с поддержкой сжатых инструкций, так уж и быть); program counter с костылями для branch prediction; блоки выборки памяти инструкций и данных; блок форвардинга и ожидания; прочую мелочь...

----

* у китайцев, с электротестом. Этот экземпляр я заказал в Дефолт-Сити и пожадничал на электротест - вот мне и урок: экономия пары сотен рублей (или сколько он там стоит, я не помню) оборачивается бессонной ночью и бессильными злобными матюками в никуда.

worklog: сдвиготрон заработал

60 микросхем буферов, из которых собран монстрический пятистадийный 32-разрядный мультиплексор. Каждый чип - 20 контактов.
4 логических чипа, на которых сделана логика переключения, по 14 пинов на каждый.
Итого 1256 контактов... и ОДИН непропай - оттуда и вылезал этот неуловимый Джо.

Джо пойман и пропаян. Сдвиготрон фигачит направо-налево, логические и арифметические сдвиги. Задержка выход-выход всего около 25 нс, если я правильно промерял. Это должно быть пять раз по Tpropagation, а документация обещает 4 нс типичное значение; плюс ещё задержка на меди. По порядку величины очень даже сошлось.

Прям-таки гора с плеч. Итого, первый кусок будущего мегадивайса -- собран!

worklog: арифметико-логический ломтик

ALU slice, то бишь.
При помощи свежесобранного анализатора погонял по операциям: работает! Суммирование/вычитание, AND/OR/XOR -- всё как надо.

Теперь надо собраться с силами и собрать ещё три "ломтика", поставить их на объединяющую плату со схемой переноса и подумать над тем, как правильно проверить 32-битную арифметику. Если 8-битную можно просто прогнать по всем возможным значениям, то тут такой прямолинейный подход точно не годится, ибо Вселенная распадётся и погаснет раньше, чем закончится перебор.

worklog: двоичный компаратор - платы приехали

И ещё обновлённые платки для логического анализатора - начать надо с него.
Плюс ещё оснастка для тестирования, чтобы не на "соплях" всё подключать, а нормальными шлейфами удобной длины.
И у меня даже все детальки уже есть.
Завтра начну собирать.

А как нормально запущу анализатор, там и до сдвигателя доберусь - я ведь до сих пор не знаю, почему у него глючит старший разряд.

После компаратора - сборка АЛУ. Один слайс уже готов и проверен, осталось сделать ещё три. Обновлённая плата со схемой быстрого переноса тоже есть и ждёт своей очереди.

После сборки и проверки можно будет считать, что блок EXECUTE готов на 75% (остаётся ещё модуль CSR, с ним придётся повозиться).

worklog: блок управления форвардингом

Блок работает внутри стадии Decode (Fetch - Decode - Execute - Memory - Writeback).

Collapse )

Нужен для проброса данных "против течения" конвейера - когда блоку вычислений понадобятся результаты работы следующих стадий, ещё не успевшие осесть в регистрах, то их надо выдёргивать прямо с промежуточных участков. Для этого должны выполниться определённые условия:
1) если надо читать из регистра с тем же индексом, в который писала предыдущая или пред-предыдущая операция (находящиеся, соотв., на стадиях Execute или Memory),..
2) и это не регистр ZERO (потому что в него выбрасываются данные, которые надо забыть; читается всегда ноль)

Если предыдущая операция была загрузкой из памяти и при этом ещё выполнились два предыдущих условия, тогда конвейер надо придержать (STALL) на минимум 1 щелчок. Пред-предыдущая загрузка из памяти задержку по-умолчанию не требует (если память успела их предоставить за 1 такт, конечно же).

Соотв., при выполнении этих условий включается мультиплексор на входе стадии E, который либо копирует данные с её же выхода (но с предыдущего такта), либо с выхода стадии M (т.е. с пред-предыдущего такта). При этом у стадии E приоритет над M, потому что если обе этих стадии нацеливают запись в один и тот же регистр, то запись из E всё равно сотрёт данные от M. Запись в регистры общего назначения не имеет побочных эффектов, поэтому перезаписанные данные не важны - важно только текущее значение.

В финальной схеме, управляющей обоими каналами RS1 и RS2, сигнал LOAD_STALL формируется как (DE_RS1 OR DE_RS2) AND E_IS_LOAD: вне зависимости от того, в какой канал надо положить данные, задержка нужна одна и та же.