Внутрь тела перейти сложнее, потому что надо получить адрес нужной итерации. Или можно проще?
Проверок осталось столько же, но сброс конвейера только один на N итераций, "jp loop".
Bolt, с аппаратными циклами сбрасывать конвейер вообще не требуется, поскольку видя совпадение PC с адресом последней инструкции цикла, мы уменьшим на 1 счётчик и если он не нулевой, просто загрузим в PC из другого регистра адрес его начала, а не PC+1. Этот более общий механизм, чем строковые инструкции из x86, поскольку позволяет организовывать циклы из нескольких инструкций без дополнительных накладных расходов.
Можно и так, конечно.
- - - Добавлено - - -
Вариант нулевой. Конвейер как бы есть, но прогоняем по нему инструкции по одной. Самый наипростейший вариант, но и самый медленный.
Вариант первый. Грузим в конвейер с одной стороны, забираем с другой, на каждом переходе ждём N тактов для заполнения. Вариант простой, но потеряется много тактов, особенно на коротких циклах.
Вариант второй. Делаем быструю djnz для коротких циклов, которая будет работать без дополнительных тактов. Вариант чуть сложнее в реализации.
Вариант третий. Делаем предсказание переходов. Плюс один блок памяти, сотня-другая ячеек в ПЛИС, но выигрываем в скорости на переходах. Вариант достаточно сложный, если заморочиться с алгоритмом предсказания. Но djnz так же выполняется, как и раньше, пусть даже за один-два такта.
Вариант четвёртый, с регистрами. Лишних тактов на djnz не тратится, но тут я вообще не понимаю как это реализовать. Нет, если тупо гнать данные, сравнивая PC и перепрыгивая на другой адрес, то всё просто. Но что делать с прерываниями внутри цикла? Какой адрес возврата сохранять в стек? Какое значение читать из регистра-счётчика (оно будет меньше, чем должно быть для текущей выполняемой инструкции)? Как перегружать поток при выходе из цикла?
Последний раз редактировалось andrews; 31.01.2020 в 11:45.
С любовью к вам, Yandex.Direct
Размещение рекламы на форуме способствует его дальнейшему развитию
andrews, планируются и недопустимые инструкции, и прерывания при недопустимых обращениях.
Три режима: ядро, пользователь, и эмуляция Z80. В режиме ядра можно всё, в режиме пользователя запрет на некоторые команды, в режиме эмуляции перехват обращения к портам для эмуляции железа. Программа в режиме эмуляции по идее вообще не должна обнаружить, что она не на железе выполняется.
Ещё может быть нераспределённая память. То есть приложению выделяется конечно же не 16 мегабайт, а сколько оно попросит (и сколько есть), в адресном пространстве будут "дырки". Можно игнорировать запись и читать 00h, а можно вызывать прерывание.
В самом простом для понимания варианте есть:
Инструкция запуска цикла адрес следующий инструкции записывает в LoopStat, а в LoopEnd и LoopCnt пишет переданные в параметрах значения. Когда PC становится равным LoopEnd мы уменьшаем счётчик и если еще не 0, то перезаписываем PC из LoopStart, иначе продолжаем выполнять код как обычно. Проблема здесь только в том, что мы либо теряем такт на перезапись PC, либо снижаем скорость выборки программы чтобы успело установиться новое значение PC при выдаче его на шину. Именно по-этому метку нужно перенести на последнюю инструкцию, тогда компаратор PC c LoopEnd скажет нужно ли заменить его на LoopStart (при условии что счётчик не 0).Код:DoLoop LoopEnd, LoopCnt LoopStart: - реально не требуется так как команда запуска цикла может вычислить эту метку сама ... LastInst LoopEnd: - метка первой команды за циклом(для простоты понимания)
Реально действия последней команды ничем не отличаются от остальных, за исключением того, что к ним добавляется уменьшение счётчика и выбор что записывать в PC. То есть, если переход в прерывание выполняется перед последней командой цикла, в стек пойдёт её адрес. Если после, то сохраняется адрес первой команды за циклом, если счётчик как раз обнулился, иначе сохраняется LoopStart. Ни эти регистры на прерывание, ни прерывание на регистры никак не влияют, поскольку нужно вернуться из прерывания и дойти до LoopEnd, чтобы этот механизм снова сработал. Если последней командой цикла стоит вызов подпрограммы, мы должны сохранить в стек либо адрес после цикла, либо LoopStart. Из такого цикла можно делать условные переходы, главное потом вернуться обратно внутрь.
Если мы хотим запустить вложенный цикл, то нам требуется сохранить LoopStart, LoopEnd и LoopCnt, а после его окончания восстановить. Или можно поручить это команде которая запускает цикл, а восстановление будет производиться при обнулении счётчика. Хотя для ситуации когда цикл не вложенный, и перед запуском счётчик и так был 0 это будет лишней работой. Может, есть смысл сделать два вида команды запуска цикла с сохранением предыдущего и без, правда тогда еще появится аппаратный флаг, чтобы указать на необходимость восстановления в конце счётчиков внешнего цикла.
Соображение по поводу конвейера и обработки прерываний: сигнал запроса прерываний должен просто заблокировать выборку следующей инструкции, заморозить PC, запретить прерывания и подсунуть в регистр инструкций команду перехода к обработчику, достаточно обычного CALL и на этом его миссия может быть завершена. Тогда вызов прерываний пойдёт по конвейеру вместе с обычными командами.
Последний раз редактировалось blackmirror; 31.01.2020 в 20:41.
Так...
Вот смотри. Есть у нас "конвейер". Допустим, на 5 тактов. Я понимаю как это сделать, и как сделать LoopCnt, но я не понимаю как выгребать из разных заковыристых ситуаций.
Выполняем длинный кусок без ветвлений.
Когда на выходе PC, на входе PC+4.
Если прилетело прерывание - что сохранить в стек?
Цикл из одной инструкции. Или из двух. Когда выполняем PC, на входе PC или PC-1. Что сохранять в стек?
В теле цикла используется счётчик. Выполняется инструкция на выходе конвейера, но счётчик-то уже на 4 уменьшился.
А тут ещё и прерывание. Что сохранять в стек? А что делать с тем, что уже выбрано? Что делать с счётчиком, который уже уменьшен?
Сохранять в стек адрес следующей инструкции, то есть которая на предпоследнем этапе? А если счётчик ушёл в ноль и выбрана ещё одна инструкция после цикла?
Ну сохранили адрес предпоследней, то есть инструкции в цикле, которая единственная, а счётчик уже обнулён. Куда возвращаться и что делать? Прокрутить цикл ещё 2^32 раз? Предусмотреть ещё один флаг?
Не, ну можно, например, доделать что уже попало в конвейер, потом уходить в прерывание. А в конвейере уже начался новый цикл.
И теперь это всё на HDL, плз.
Я, наверное, тупой, раз не понимаю как такие очевидные вещи делаются.
Регистрам Loopcnt - нет.
- - - Добавлено - - -
Тут другая проблема актуальна.
Выбираем 5 инструкций. Но 3 выбраны, и это джамп, а 2 уже уползло в запретную страницу, и они уже не понадобятся. Это как разруливать? Запретить программисту располагать код ближе, чем на 5 байт к концу страницы?
Эту тему просматривают: 1 (пользователей: 0 , гостей: 1)