Ну и что процессор будет делать в этом случае?
Вид для печати
Да, поэтому адресу тусуются остальные трапы: TRAP10_6500, TRAP10_6600, TRAP10_7, TRAP10_40.
- - - Добавлено - - -
Остаются два бесхозных трапа 210 и 75040.
- - - Добавлено - - -
Я думаю, они идут по тому же адресу, т.к. преддекодер их не выделяет. Стало быть все трапы обрабатываются едино.
Я думаю, что нужны AD, SYNC, AR, DIN, RPLY, RDAT,
WR7, MDFY, BUF_RES, IO_RCD, IO_CMD, IO_RD, IO_IN, WR1, WR2, RCMD_SET, THANG, IO_RCD1, CREQ, IOCMD_ST4, IOCMD_ST3, IOCMD_ST0, ABORT, ALU_WR, IO_START, IOP_STB, ALL_RDY, IORD_ST1, BIR_STB, BRD_WQ, MC_DRDY, SK, BRA, BRA_REQ.
Регистры: PC1, PC2, PC, PSW, CPSW, регистры с кооторыми работает сама команда.
Надеюсь, этого хватит.
Выборка кэшированной инструкции. Если есть запрос на прерывание, то переход к обработке запроса, а там прерывание по приоритету. Т.к. у TRAP4 самый высокий приоритет, то оно и исполнится.
А после отпускания DCLO как там ожидается прямой фронт ACLO? И как будет установлен запрос на прерывание по нулевому вектору HALT?
Сигналы ABORT и THANG тебе не нужны, они неактивны при проявлении бага.
Фрагмент исполняемого кода, на диаграммах показан момент после MUL
Быстрая шина, баг не проявляетсяКод:
180 000434 012700 000001 tst0: mov #1, R0 ; тест ошибки предвыборки
181 000440 012701 000002 mov #2, R1 ;
182 000444 012702 000003 mov #3, R2 ;
183 000450 012703 000004 mov #4, R3 ;
184 000454 070400 mul R0, R4 ;
185 000456 011704 mov @PC, R4 ;
186 000460 005200 inc R0 ;
187 000462 005201 inc R1 ;
188 000464 005202 inc R2 ;
189 000466 005203 inc R3 ;
190 000470 000000 halt ;
Скрытый текст
Медленная шина (+5 тактов), баг проявляется
Скрытый текст
- - - Добавлено - - -
После аппаратного сброса матрица прерываний выдает специальный код, и оно крутится на первом адресе пока ACLO не деактивируется, все остальные прерывания не обрабатываются.
В таблице векторов прерываний, которую я расшифровывал, все описано же было.
Высший приоритет имеет прерывание по спаду ACLO, вектор 0x00 в режиме HALT.
А по фронту ACLO, как я понимаю из той же таблицы, идет удержание состояние WAIT.
- - - Добавлено - - -
Я доверчивый. Мне говорят - не проявляется, я и верю)
Первый график короток по времени, чтобы понять, сколько раз.
И да, еще раз повторюсь, счетчики после неправильной команды не сбиты.
Примерно глянул на графики. Заодно нашел у себя в описаниях ошибку связанную с IO_CMD. Если бы знал ее раньше, то может быть и без графиков догадался, где собака порылась)
Я думаю, что проблема в том, что блок ввода-вывода, работающий асинхронно, в конце команды MOV @PC,Rn выдает результат кеширования следующей инструкции в регистр BIR (по сигналу BIR_STB) прям в тот момент, когда этот регистр уже используется. Т.е. если память быстрая, то BIR (кэш инструкции) успевает обновиться до того, как будет использован для декодирования следующей инструкции INC R0. А если память медленная, то инструкция уже декодируется, и в этот момент прилетает новое значение BIR, накладываясь на старое. Подробно изучать сейчас не будут, ибо поздно, но сто процентов, что собака порылась именно здесь. Но думаю, что возможных накладок после подобной команды может быть больше и интереснее.
- - - Добавлено - - -
Да, так и поехало.
В нормальном режиме сперва прилетает новое значение в BIR (кэш), и после этого оно защелкивается и декодируется по IR_STB.
А в ненормальном все меняется местами. В BIR уже есть значение, оно защелкивается по IR_STB, и тут сразу же прилетает новое значение BIR с опозданием. В результате попадаем в порочный круг, когда значение в кэше всегда отстает на одно значение от реально ожидаемого, т.к. прилетает после IR_STB. А так как сбившийся кэш сбросить некому, все так и идет по кругу. И, естественно, INC R0 выполняется два раза. При этом счетчики PC1 и PC2 не портятся и никуда не отстают. Это ложная теория. Сбросить неправильный кэш помогут две команды, которые делают это принудительно посредством IO_CMD. Это команда STEP. И любая команда начинающаяся с перекеширования инструкции (адрес микрокоманды 0x21).
Лучше в эмуляторе, в настройках, галочку поставить... По умолчанию, ошибка включена, но если кому надо - галочку снять можно :)
У меня для ВМ2 сделано исправление этого бага по флагу компиляции. Каждый сам может решить и выбрать нужен ли ему это баг в системе или нет.
- - - Добавлено - - -
Здрасьте, приехали. Там именно теряется одно обновление PC2+2 из-за перезаписи PC2 при выдаче адреса в фазе @PC и предвыборка делается по адресу на 2 меньшему чем должно быть. В итоге поток инструкций отстает на 1 слово в отличие от нормального исполнения. Если поставить два графика рядом, то это не очень хорошо видно из-за разного быстродействия памяти, но если сравнить по циклам микроинструкций, то видна вставка исполнения inc R0 вместо исполнения следующей inc R1. Схема полагает что прочитано 2(PC2), то есть следующая inc R1, а реально читается @PC2, то есть inc R0. Я сделал фикс в виде блокировки перезаписи PC2 и он прекрасно работает.
Ну, сравнил:
Скрытый текст
Верхний график в вдвое меньшем масштабе, поэтому вот то PC2=460 длится ВДВОЕ дольше чем на нижнем графике. Там-то и выполняется лишнее присваивание PC2=460 и выполняется лишний INC R0. Ты видишь тут только последовательность: 460, 462, 460, 462, 464. Это ситуация верная, если нет ошибки. А реально, в случае глюка, это: 460, 462, 460, 460, 462, 464.
- - - Добавлено - - -
Я вечером сделаю диаграмму с PC2 привязанным к шине и микрокоду, там будет виднее.
И это абсолютно правильно. Попросили инструкцию по 460 - получили INC R0. Попросили два раза по адресу 460 - получили два раза. Баг не в том что неправильный счетчик в момент исполнения инструкции, а в том что сначала исполняется инструкция для которой завершилась поздняя предвыборка, а потом она выбирается и исполняется еще раз.
Пересобрал диаграммы с действительно нужными сигналами, а не со запрошенной свалкой.
Код тоже немного поменял, интересно как оно себя дальше ведет:
Процессор здорового человека:Код:180 000434 012700 000001 tst0: mov #1, R0 ; тест ошибки предвыборки
181 000440 012701 000002 mov #2, R1 ;
182 000444 012702 000003 mov #3, R2 ;
183 000450 012703 000004 mov #4, R3 ;
184 000454 070400 mul R0, R4 ;
185 000456 011704 mov @PC, R4 ;
186 000460 005200 inc R0 ;
187 000462 005201 inc R1 ;
188 ; inc R2 ;
189 ; inc R3 ;
190 000464 000401 br 1$ ;
191 000466 000000 halt ;
192 000470 000000 1$: halt ;
193 ;_____________________________________________________________________________
194 ;
195 000472 012700 000001 tst1: mov #1, R0 ; тест ошибки предвыборки
196 000476 012701 000002 mov #2, R1 ;
Скрытый текст
Процессор курильщика.
Скрытый текст
Там проблема в фазах bir_stb и ir_stb.
Последовательность на шине такая:
- исполняется mov @PC, R4
- читаем 460, предвыборка inc R0
- читаем 460, это чтение по @PC из ьщм @PC, R4
- читаем 460, снова запущенная предвыборка inc R0
И тут начинается самое интересное, мы приходим на 00 (77 на диаграмме), и там формируется Конец Команды (set_cend).
Если предвыборка 460 завершилась, то все хорошо, код inc R0 попадет в регистр инструкций и все исполнится как обычно.
Но если предвыборка НЕ завершилась, то процессор все равно берет код инструкции из буферного регистра (там был inc R0 от предыдущей предвыборки) и выполняет его. Следующая инструкция будет по результатам второй предвыборки 460 которая перед этим не завершилась. Таким образом, в IREG inc R0 попадает дважды. А дальше оно уже по факту смещено. Процессор запускает предвыборку по адресу 462, но на самом деле еще выполняется предвыборка по адресу 460, и вместо помещенной в конвейер запущенной 462 будут получены сначала 460-ые и исполнены, и только затем 462-ые.
Особенности работы кэша
Любая команда перед декодированием попадает в кэш команд BIR (буферный регистр инструкций). Если кэш команд недействительный (предыдущее значение уже использовано, а новое еще не загружено), то блок декодирования команды будет ожидать загрузки нового значения в BIR. Существует несколько событий и состояний процессора, делающих кэш команд недействительным.
События отличаются от состояния тем, что события имеют кратковременный характер и длятся не более 1-2 тактов CLCI, а состояния могу длиться более продолжительное время.
События сбрасывающие кэш:
- RESET - событие сброса микропроцессора по ACLO.
- CLR_CEND - происходит после защелкивания текущего значения кэша по сигналу IR_STB в регистре инструкций IR. Это необходимо для того, чтобы сообщить кэшу, что кэшированную команду использовали, и можно кэшировать новую.
Состояния сбрасывающие кэш:
- BUF_RES - возникает в двух случаях:
- Если при записи в память, регистр адреса RA совпал регистром PC1. А регистр PC1 всегда указывает на следующее слово команды, в независимости от того, кэшировано оно в BIR или нет.
- От блока таймаута пришло событие TO_RPLY.
Отменяется это событие по RESET или же по записи в регистр R7, кроме шагов микропрограммы 0x01 (выборка кэшированной инструкции), и шагов 0x10 и 0x16 (кэширование следующего слова команды/данных в некоторых операциях с двумя операндами, когда источник расположен в памяти).
- WORD27 - состояние запрета кэша команд. Запрашивается некоторыми методами адресации, чтобы использовать кэшированное слово следующей инструкции в качестве данных.
Отменяется по RESET или ABORT, либо же по микрокоманде ожидания готовности BRD. Упрощенно использование этого состояния микропрограммой выглядит так:
- Запретить кэш. При этом автоматически PC1=PC2 (в обычном режиме PC2 опережает PC1 на 2, и указывает на следующий за кэшированным словом адрес).
- Использовать BIR по своему усмотрению, например, как смещение для адресации X(Rn).
- Запросить чтение в BRD какого-то слова (необязательный шаг).
- Ожидать готовности BRD (момента, когда слово прочитано) и отменить запрещение кэша.
Следует заметить, что отмена события запрещения кэша не делает содержимое кэша действительным, и микропрограмма выборки следующей команды должна быть запрошена не по адресу 0x01 (выборка кэшированной инструкции), а по адресу 0x21 (выборка некэшированной инструкции). Только после этого кэш команд станет опять действительным и может быть использован.
- IO_CMD - принудительный сброс BIR в микрокомандах 0x21 (выборка некэшированной инструкции) и в инструкции процессора RESET. Состояние длится до тех пор, пока блок ввода-вывода не освободится, и не начнет операцию чтения (кэширования) команды (сигнал IOP_STB). На протяжении всего этого состояния всякое завершение возможного предыдущего асинхронного цикла чтения в регистр BIR будет игнорироваться. Это сделано для того, чтобы не произошла ситуация следующего рода - в команде кэширования (0x21) запросили чтение BIR, а предыдущая микрокоманда тоже читала BIR, и асинхронный результат этого чтения с запозданием прилетел в кэш и нарушил всю логику работы.
Теперь перейдем к единственному сoбытию, которое делает кэш действительным. Это завершение чтения регистра BIR. Если ни одно из предыдущих событий и состояний не активно, то после чтения BIR, кэш становится действительным и может быть использован для декодирования команды. Чтение BIR запрашивается в следующих микрокомандах:
- 0x01 (выборка кэшированной инструкции). В момент защелкивания из BIR кода инструкции в регистр инструкции IR сразу инициализируется запрос чтения в BIR следующего слова.
- 0x10 и 0x16 (кэширование следующего слова команды/данных) в некоторых операциях с двумя операндами, когда источник расположен в памяти.
Ошибки использования кэша:
В некоторых микрокомандах содержатся ошибки, приводящие к сбою или ошибкам в работе кэша. Ошибка - это однократное событие, сбой - это устойчивое состояние.
- Ошибка команд расширенной арифметики EIS (MUL, DIV, ASH и ASHC). Из-а того, что порядок кодирования операндов в слове инструкции поменян местами относительно всех остальных команд, стандартные схемы определения модификации R7, если этот регистр задействован в качестве приемника - не работают. Из-за чего после окончания EIS-инструкции идет переход на микрокоманду 0x01 (выборка кэшированной инструкции) а не на микрокоманду 0x21 (выборка некэшированной инструкции). Это приводит к тому, что даже если R7 в ходе выполнения инструкции изменился, выборка следующей инструкции будет из кэша BIR, а там находится инструкция следующая за EIS. Однако, далее работа кэша восстанавливает в нормальном режиме.
- Ошибка адресации (R7) в качестве источника в двухоперандных команд, приводящая к сбою в работе кэша.
При работе с кэшем обязательно соблюдать следующее правило - сперва сделать недействительным текущее значение кэша (не важно, использовалось оно или нет), и только потом запрашивать чтение нового значения в кэш. Если эту последовательность не соблюсти, то произойдет ситуация наложения новых данных в кэше на старые, результат которого будет зависеть от времени прихода асинхронного ответа на запрос чтения контроллера ввода-вывода.
Выполнение микрокоманды 0x01 (выборка кэшированной инструкции) может начинаться как минимум тремя способами (четвертый относится к блоку таймаута, и здесь не рассматривается):
- Кэш недействительный, ожидаем чтение нового значения BIR, которое запросила предыдущая микрокоманда 0x21 (выборка некэшированной инструкции).
- Кэш действительный, можно сразу использовать значение BIR. Фоновых асинхронных запросов чтения шины нет.
- Кэш действительный, можно сразу использовать значение BIR. Не окончен фоновой запрос чтения шины в регистр BIR. Является последствием сбоя в работе кэша.
Рассмотрим возникновение ситуации описанной в третьем пункте.
Микрокоманда выполнения операции с двумя операндами, когда источник находится в памяти, имеет ошибку следующего вида:
Типы адресаций источника (R7)+, @(R7)+, X(Rn) и @X(Rn) имеют специальные обработчики, использующие BIR в качестве данных и сбрасывающие кэш.
Типы адресаций источника (R7), -(R7), @-(Rn) специальных обработчиков не имеют, и выполняются для всех регистров одинаково. Кэш не сбрасывается.
Вторым этапом микропрограмма определяет, нужно ли делать кэширование только что использованного BIR, или не надо. И определяет она это по признаку RI2, который установлен, если адресация источника (R7), (R7)+, -(R7), @(R7)+, @-(R7), X(Rn), @X(Rn). Как видно, адресации (R7), -(R7), @-(Rn) тоже попадают в обработчик компенсации, хотя кэш НЕ использовали и НЕ сбрасывали.
Обработчик компенсации запрашивает цикл чтения BIR по адресу PC2, затем делает PC1=PC2, и PC2=PC2+2.
Далее, если приемник - регистр, выполняется цикл ALU для заданной инструкции, и если приемник не равен R7, идет переход на адрес 0x01 (выборка кэшированной инструкции). Таким образом, если асинхронный цикл чтения BIR, запрошенный обработчиком компенсации, успел завершиться до защелкивания BIR в IR, кэш продолжит нормальную работу. Если же цикл чтения BIR завершился после защелкивания уже имеющегося BIR в IR, то кэш сразу же станет действительным, но все равно будет выдан запрос чтения BIR. Таким образом, декодироваться и выполняться будет инструкция запрошенная в предыдущем цикле, т.е. с отставанием на одно слово. И этот процесс будет повторяться, пока какая-либо команда не сделает кэш недействительным одним из описанных выше способов.
В случае, если приемник - память, то после компенсации будет переход на микрокоманду 0x17 и декодирование адресации приемника.
Что происходит с указателями PC1 и PC2 после обработки адресаций источника (R7), -(R7), @-(Rn):
Как видно, никакого нарушения в логике работы в этих местах не будет, и все последующие нарушения происходят исключительно из-за отсутствия сброса кэша.Код:(R7):
RA=PC1 IO_RD, IO_IN // Инициировать цикл чтения шины
PC2=PC1
-(R7):
PC2=PC1-2
RA=PC2 IO_RD, IO_IN // Инициировать цикл чтения шины
@-(R7):
PC2=PC1-2
RA=PC2 IO_RD, IO_IN // Инициировать цикл чтения шины
//----------------------------------------------------------------------
WAIT_BRD // Ожидание готовности чтения BRD
ACC=BRD
RA=ACC IO_RD, IO_IN // Инициировать цикл чтения шины
Я в свое время пытался отфильтровать на RI2 адресацию (PC), но оно не помогло, крашилось. Похоже что там еще нужное в "компенсаторе" делается, нельзя его просто так скипнуть.
Просьба к @Vslav'у сделать несколько диаграмм со следующими командами:
1. Простая MOV R1,R0, за которой следует отсутствующая ячейка памяти.
2. Команда MOV #1234,R0, причем слово аргумента (1234) находится уже в отсутствующей ячейке памяти.
3. Команда MOV (R1),R0, за которой следует существующая ячейка памяти, а R1 ссылается на несуществующую ячейку памяти.
4. Команда BRA куда-нибудь в существующую ячейку памяти, так что после BRA сразу идет отсутствующая ячейка памяти
5. Можно еще для чистоты эксперимента сделать MOV R0,R7, за которой следует отсутствующая ячейка памяти, а R0 указывает на существующую ячейку памяти.
Сигналы нужны все те же, что и в диаграммах ошибки кэша, только добавить к ним: TO_RPLY, TOVF, ABORT, THANG, TEVENT, RCMD_SET, TO_BLOCK, IOCMD_ST0..4.
MOV выполнится, потом будет исключение.
Тут сразу значение PC при исключении не скажу.
Будет исключение по выборке по адресу R1.
Переход выполнится нормально, без исключений.
Должно тоже пройти нормально, без исключений. Я все это уже тестировал, диаграмки завтра постараюсь сделать, увидим сильно ли я ошибся :)
Мне нужны именно точные диаграммы на асинхронной модели)
@Vslav, ты не забыл про диаграммы?