Комментарии от COKPOWEHEU

Именно для подпрограмм это может быть неудобно. При переключении контекстов придется разматывать этот стек и пересохранять его в память.

У WCH реализована похожая штука - аппаратное сохранение несохраняемых регистров (t*, a*) при входе в прерывание. Благодаря этому прерывание выглядит как обычная функция: те регистры, о которых обычно заботится caller, сохраняются аппаратно. Остальные - самим обработчиком. Но и тут я умудрился наступить на грабли. При реализации многозадачности этот аппаратный стек надо вручную отключать чтобы сохранить регистры туда, куда мне надо, и восстановить потом из нужного места, а не из стека.

Но, повторю, с прерываниями это проще, чем с функциями. У них почти всегда нулевая вложенность.

Проще выделить лишний блок в MMIO или CSR, чем вот так извращаться. И в принципе, именно так и делают.

Георгий Курячий Тем не менее в стандарте прописаны именно hints, а CSR таких нет, всё отдано на откуп производителю

Это не конвенция, а аппаратное ограничение. Секцию .text бесполезно располагать в области MMIO, в секцию .data - во флеш-памяти. Переназначить-то, конечно, можно, но работать не будет.

Георгий Курячий Это договорённость о том, где какая память размещена, причём вариантов этой договорённости несколько. как по мне — конвенция по определению.

Похоже, что 32 или даже 16 регистров как раз и оказалось оптимальным. Все данные туда так и так не загонишь, а в алгоритмах слишком часто встречаются задачи либо провести с переменной какую-то простую операцию и положить на место, либо наоборот работа с огромными массивами данных, которые в регистры все равно не влезут. Плюс ограниченное количество битов на хранение адреса, плюс необходимость сохранять - восстанавливать.

Георгий Курячий Это вы просто компиляторов мало писали).

Смысл в том, что, допустим, .data располагается прямо с начала оперативной памяти - 0x2000 0000. Этот адрес слишком велик, чтобы кодировать его в imm-части инструкции. Придется сначала грузить старшие биты в какой-нибудь РОН, а потом через imm добавлять смещение. Но можно задокументировать gp (или tp, наверное) на 0x2000 0000 + 2048, тогда доступ к первым 4 кБ будет на целую инструкцию проще.

Для общего ознакомления было бы неплохо показать хотя бы одну альтернативную модель памяти. Вот, например: https://niiet.ru/wp-content/uploads/2025/10/%D0%A0%D0%9F-%D0%9A1921%D0%92%D0%93015.pdf (сама железка https://niiet.ru/product/%D0%BA1921%D0%B2%D0%B3015/) глава 6 "организация памяти". Видно, что секция .text располагается с 0x8000 0000, секция .data с 0x4000 0000, секция MMIO c 0x2000 0000 ну и так далее.

Как следствие - акцент на специфичных для RARS адресах и костылях стоило бы убрать. Операционная система сама назначает права доступа тем областям памяти, которым хочет. А при наличии MMU - может их еще и перетасовать.

Вот эти костыли времен MIPS уж точно стоит убрать.

Георгий Курячий Из Rars? Welcome. Я бы не взялся.

А в чем подвох? Вроде все нормально читается. В **некоторых** ядрах нельзя прочитать по нечетному адресу **слово**. Но уж с байтами-то даже там проблем нет. А другим вообще плевать на выравнивание.

Уже введение второго **уровня привилений**, M-mode вдобавок к U-mode. Исправляем терминологию. MMU тут вообще никакого отношения не имеет. Насколько я слышал, даже полноценный Linux можно запустить на машине без MMU. С определенными огранияениями (fork не работает, например), но все же.

Георгий Курячий Кажется, замечание мимо кассы. Привилегии — это привилегии, какие-от команды на каком-то уровне недоступны, вот и всё. Вопрос именно в том. В каких случаях в памяти не надо заранее явно выделять место, куда загружено ядро.

Вот потому и много, что зачем-то идет рассмотрение тонкостей эмулятора, которые потом в курсе нигде не используются.

Георгий Курячий Rars используется в курсе чуть менее, чем всегда.

Это иногда приводит к другим проблемам. Например, адреса меток можно загружать только через la. Даже если нужен абсолютный адрес начала ОЗУ (инициализация регистров gp, sp, инициализация переменных из флеша и т.д.). Как заставить программу внутри .text обращаться к себе через la, а между .text и .data через li я так и не понял. А ведь .text, в отличие от .data, может перемещаться.

Но 2^12 это и так 4096. Отдельно стоит отметить, что адрес кратен 2, а не 4. Расширение С учитывается даже тут.

Скорее, неинтуитивная.

"Ситуации, когда целочисленное переполнение в вычислениях необходимо проверять, были типичны для 8- или хотя бы 16-битных машин". RISCV изначально 32-битный, его еще поди переполни.

И к необходимости программисту использовать div/rem в правильном порядке

Георгий Курячий Наоборот, избавило бы его от этой необходимости, см. далее

Разве что речь идет о двоичных порядках. Умножение все же относительно простая операция, которая выполняется всего раза в два медленнее. Вот деление - да, десятки тактов на него это норма.

Георгий Курячий Вы так и не показали мне алгоритм / схемотехнику, при помощи которой умножение можно сделать за два такта

ЕМНИП, там в другом прикол. Он не должен совпадать, если нас интересуют И div, И rem. По вполне очевидной причине - аргументы второй инструкции должны быть теми же, что у первой, иначе и результат будет другой.

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

Георгий Курячий Если за какую-то операцию (хоть за преобразование Фурье) отвечает «отдельный аппаратный блок», она действительно может пройти за два такта — загрузить, выгрузить. Тогда почему деление медленное?

LecturesCMC/ArchitectureAssembler2026/02_MemoryRegisters/COKPOWEHEU (последним исправлял пользователь FrBrGeorge 2026-02-23 14:29:58)