Внимательное чтение
описания системы команд привело меня к следующему:The indirect jump instruction JALR (jump and link register) uses the I-type encoding. The target address is obtained by adding the sign-extended 12-bit I-immediate to the register rs1, then setting the least-significant bit of the result to zero...
Чуть ниже комментарий:Clearing the least-significant bit when calculating the JALR target address both simplifies the hardware slightly and allows the low bit of function pointers to be used to store auxiliary information. Although there is potentially a slight loss of error checking in this case, in practice jumps to an incorrect instruction address will usually quickly raise an exception.
И ещё чуть ниже восхитительное (с ещё одним комментарием):The JAL and JALR instructions will generate an instruction-address-misaligned exception if the target address is not aligned to a four-byte boundary.Instruction-address-misaligned exceptions are not possible on machines that support extensions with 16-bit aligned instructions, such as the compressed instruction-set extension, C.
Ради экономии двух байтов авторы спецификации ввели исключение неправильного адреса команды, которое будет висеть и ничего не делать более 99,9999999% времени. Но реализовать его надо, иначе уже не RISC-V.
Если сбрасывать в ноль два младших байта адреса команды, то все переходы для 32-хбитных команд будут верны, как и переходы для 16-тибитных команд (сжатый набор команд, расширение C). В случае сжатого набора команд половину, в среднем, адресов переходов придётся дополнять NOP.
Но у нас есть NOP fusion (если после команды NOP, то мы этот NOP отбрасываем), о котором я знаю с 2007 года, когда реализовывал модель MIPS, и о котором авторы документа не упоминают. Что интересно, выравнивание по слову однозначно приведёт к простому случаю nop-fusion, реализуемому даже во встраиваемых системах. Тем не менее, они рассматривают стек адресов возврата, что много более недавнее изобретение (страницы 39-40 документа по первой ссылке) и много более сложное, и даже дают правила работы этого стека (таблица вверху страницы 40).
Итак, авторы RISC-V заставили всех иметь редко работающее исключение, что требует (пусть и малой) площади кристалла и энергии во время работы ядра, и требует обязательного тестирования (пусть и небольшого).
Вспоминая мои проблемы с командой в цикле задержки перехода (branch delay slot) при реализации MIPS с внеочередным выполнением команд, я смело могу заявить, что переходы являются одной из самых сложных команд процессоров всех времён. Вероятность того, что вы там напутаете и сделаете что-то слишком сложным, весьма высока.
Остальная часть RISC-V меня скорее радует, чем наоборот.
Например, они экономят пространство команд, предлагая переставлять операнды в операциях сравнения (a ≤ b это b ≥ a, если у нас есть ≤, то ≥ может быть реализовано на уровне ассемблера, простой перестановкой операндов), а не вводя новые коды команд.
Переменная длина команды выглядит, скорее, нужным решением, пусть и редко используемым (может породить исключение неверной команды, так это и так должно быть).