MARS, по-видимому, содержит ошибку ассемблера в b
инструкциях, когда имя метки также является допустимой инструкцией mnemoni c. Это заканчивается как инструкция перехода к следующему.
Изменение имени метки с AND
на AND_TOP
привело к правильной сборке. Эраклон обнаружил, что с помощью инструкции j
тоже сработало. (:
вместо операндов устраняет неоднозначность токена как метки вместо инструкции, поэтому это ошибка в MARS, а не ошибка в вашем коде. clang прекрасно собирает ваш исходный код. Не что вы можете запустить его вне MARS, это зависит от системных вызовов MARS и ветвей без слотов.)
Я тестировал в Mars 4.5 под Java OpenJDK 1.8.0_232 на Arch GNU / Linux и воспроизвел результат @ Эраклона. (Но рассуждения в этом ответе неверны.)
Обе b AND
инструкции собираются в 0x043fFFFF
(с перечисленной инструкцией bgez $0, AND
), поэтому цель перехода - это инструкция сразу после ветви . (Какой будет задержка на реальном MIPS). Как вычислить целевой адрес перехода и целевой адрес перехода? показывает, что инструкции относительного перехода MIPS имеют I-тип и расширяют знак на 16 бит непосредственно (младший 16 слова инструкции) и сдвиг влево на 2. (Или посмотрите на это без смещения как смещение в словах). Относительно конца интервала задержки ветвления. Таким образом, смещение -1
возвращает нас к инструкции после ветви.
Также обратите внимание, что 0x043f
не является правильным кодом операции и регистровой кодировкой для bgez
. Это должно быть 0x0401
для bgez $zero
. (http://www.mrc.uidaho.edu/mrc/people/jff/digital/MIPSir.html показывает кодировки в двоичном виде). Согласно llvm-objdump -d
(после сборки .word 0x043fffff
с clang -target mips
) это фактически кодирует 4 3f ff ff synci -1($1)
. Интересно, была ли ошибка MARS ORing в значении -1
, которое было шире, чем следовало бы, перезаписывая несколько старших байтов?
(bgez $0
- это один из способов кодирования безусловной относительной ветви в MIPS. Другой способ - beq $0,$0, target
. Отдельного кода операции не существует, нужно просто выбрать одну из b...
машинных инструкций I-типа с вводными данными, которые всегда верны.)
MARS имитирует эта неправильно собранная инструкция как ветвь - всегда с закодированным смещением: она фактически проходит через ветвь . Или при включенном параметре «Настройки» -> «Задержка ветвления» команда после ветвления выполняется дважды: один раз как интервал задержки, один раз как цель ветвления.
Так что, очевидно, симулятор действительно не декодирует из машинного кода, даже если вы включаете настройки-> самоизменяющийся код. Или это просто дисплей, который сломан? IDK, на самом деле не имеет значения, это 100% ошибка, и вместо того, чтобы указывать на симптомы, кто-то должен просто посмотреть на источник MARS и исправить его.
Использование другого имени метки дает правильные результаты: первый b AND_TOP
собирается в 0x0401fffb
, а MARS перечисляет его как bgez $0, 0xfffffffb
. (Обратите внимание на смещение цифры c в списке вместо имени метки AND.)
И оно имитируется правильно, причем эти ветви идут в нужное место.
I Я не проверял вашу логику c, но она кажется слишком сложной. Обратите внимание, что la $a0, ($t0)
- это безумный способ написать move $a0, $t0
. Очевидно, MARS это позволяет. Впрочем, не было никакой причины загружаться с counter
; Вы можете обнулить регистр с помощью addu $t0, $zero, $zero
или чего угодно еще. Или напишите это как move $t0, $zero
.
Также это глупо:
beqz $t0, display #If $t0 equals 0 send to display function
b AND_TOP #send back to AND function if not
display:
Просто bnez AND_TOP
вместо условного перехода через безусловную ветвь.
Кроме того, ни Комментарий добавляет что-либо к пониманию. Если есть что сказать о , почему вы прыгаете, или значение semanti c (например, в терминах переменных высокого уровня, а не имен регистров), то укажите это в комментарии. , например, bnez $t0, count_loop # more bits left to count?
Конечно, как указывает @Eraklon, вся ваша логика ветвления c очень сложна. Просто выделите младший бит и добавьте его в счетчик, будь то ноль или единица.
Или, если вы заботитесь о производительности, замаскируйте четные и нечетные биты, сдвиг вправо на 1 и addu. Тогда у вас есть 16x 2-битные аккумуляторы, упакованные в регистр. Повторите с другой маской, пока у вас не появятся байты, затем либо продолжайте, либо используйте трюк умножения, чтобы байты суммировались в старший байт. (См. Быстрые вопросы и ответы по поп-счету здесь о переполнении стека для ответов bithack, или https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel. Ваш метод похож на https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetNaive, но более сложный. Есть варианты среднего уровня, например, очистка младший установленный бит и счетчик итераций для его обнуления.)