Я изучаю ассемблер. Я понимаю, что операция CMP R1 R2
устанавливает биты флагов (перенос, переполнение, ноль, знак и т. д.) В соответствии с результатом R1-R2.
И я понимаю, что инструкции условного перехода JX, такие как JA, JBE, следуют после CMP. Если условие битов флага совпадает, инструкция JX заставляет IP переходить на указанный адрес.
Чего я никогда не понимал, так это «Испытанные условия» на прикрепленной мною картинке.
CMP R1 R2
JAE где-то
Приведенный выше код, очевидно, переходит куда-нибудь, если R1 больше или равно R2. Если R1 = 0111 и R2 = 0110, JAE перескочит куда-нибудь. В таком случае,
R1-R2 = 0111-0110 = 0111+1010 = 10001 = 0001 with carry bit set
обратите внимание, что я добавил 2 дополнения к 0110 вместо вычитания 0110, потому что микроконтроллеры вычисляют таким образом, как я знаю
Но в учебнике сказано, что JAE будет прыгать, если флаг переноса равен 0. Мои вычисления показывают, что C = 1, если R1 больше, чем R2. Другие примеры показывают, что C = 1, если R1 больше R2. Нет проблем со знаком.
Так что плохого в «испытанных условиях»?
Почему вы вычисляете 111-110, используя сложение и отрицание второго аргумента, и вычитаете состояние флагов из этого сложения? CF и другие флаги относятся к вычитанию, не имеет значения, выполняется ли это внутри путем добавления отрицательного значения, а 111-110 равно 1 с CF = 0, ZF = 0, PF = 0 и т. д.
@ Ped7g Насколько я знаю, в микропроцессоре нет вычитателя. Таким образом, требуется дополнение до 2 и добавление его сумматором.
Вычитание - это не то же самое, что сложение дополнения до 2, потому что результирующие флаги, как вы видели, отличаются.
@hskim, к сожалению, я не изучал схемы процессоров 8086 или новее x86, поэтому я не знаю, есть ли у них только сумматор, но если они есть, вокруг него должна быть какая-то «обертка» вычитателя, чтобы исправить флаги после добавления должны быть установлены так, как их определяет инструкция sub
. Я могу просто заверить вас, что флаги имеют отношение к вычитанию, то есть CF = did_borrow и 111-110 не нужно заимствовать -> CF = 0. Понятия не имею, как это реализовано в транзисторах.
При использовании jae
числа рассматриваются как беззнаковые. Таким образом, добавление двух дополнений к числу не эквивалентно вычитанию исходного числа. Вот почему результаты флагов разные. В вашем примере 7-6 - это не то же самое, что 7 + 10 (это 10, а не «-6»).
вычитание реализовано в логике как сложение с инвертированным вторым операндом и инвертированным переносом в lsb. Независимо от того, инвертируется ли выполнение msbit и называется заимствованием, зависит от конструкции архитектуры, некоторые делают то же самое, некоторые - нет. Все флаги можно правильно разрешить. a = b + c = b + (-c) тождество было истинным в математике задолго до электричества, гораздо меньше транзисторов, гораздо меньше двоичной логики и тем более двоичного дополнения.
Столбец протестированных условий описывает, что делает логика, лучшая документация дает понять при переходе, если больше означает подписанный или неподписанный, поскольку флаги имеют значение, также имеет значение, инвертируется ли перенос в заимствование на выходе из вычитания ( сложение с минусом). Лучше, конечно, иметь хорошую документацию, которой явно нет, но, по крайней мере, она показывает проверенные условия, чтобы вы могли провести несколько экспериментов с логикой, чтобы увидеть, как работают флаги, затем мы прыгаем, если переносим, или прыгаем, если не продолжаем владеть за меньшую или большую (или равную) ....
а не многие из этих комбинаций, которые вам действительно не нужны.
Это вычитание
R1-R2 = 0111-0110
реализуется так в логике
1
0111
+ 1001
========
закончить математику
11111
0111
+ 1001
========
0001
поэтому выполнение (беззнаковое переполнение) равно 1, подписанное переполнение равно 0, так как перенос и выполнение до совпадения msbit также может определить это из msbit операндов и результата. если msbit операндов совпадают друг с другом, но msbit результата не совпадает с msbit, то подписанное переполнение.
не ноль, поэтому флаг z будет равен 0, а бит msbit не установлен, поэтому флаг n не будет установлен.
следующий вопрос: выполняет ли эта архитектура инвертирования флаг переноса при вычитании, делая его заимствованным, или они переносят его прямо?
В любом случае у вас есть четыре основных флага: перенос, подписанное переполнение, отрицательное значение и ноль. С хорошей документацией вы получите список флагов для условия. Вы как бы знаете в своей голове, хотите ли вы больше или меньше или что-то еще, этот маленький карандаш и бумажный тест, вместе с тем, чтобы сделать это на процессоре и сбросить флаги, чтобы увидеть, инвертирует ли эта архитектура выполнение, также читая docs, чтобы увидеть, затронуты ли все флаги рассматриваемой инструкцией теста, а затем просмотрите различные проверенные условия, чтобы увидеть, какие из них соответствуют вашему результату.
Ничего такого. Если R1 больше или равно R2, нет необходимости заимствовать при вычитании R2 из R1, поэтому бит переноса очищен.