Смотрите x86 тегов вику для набора инструкций справочного руководства, и много хороших ссылок на справочные материалы и учебники.
Требуется достаточно кода для разбиения целого числа на цифры ASCII, которые необходимо учитывать в функции.
Это оптимизированная и исправленная версия функции print2Digits @ hobbs. (Я также испробовал версию в своем ответе, так что это тоже правильно, но оставил оптимизацию для этого).
print2Digits:
;; input in AL (0-99).
;; clobbers AX and DX
cbw ; zero AH. Sign-extending AL does the job because AL is only allowed to be 0-99.
; omit this step if you can easily have the caller use the full AX, i.e. zero AH for us
mov dl, 10
div dl ; quotient in AL(first (high) digit), remainder in AH(second (low) digit)
add ax, 0x3030 ; add '0' to al and ah at the same time.
mov dl, ah ; save the 2nd digit
mov ah, 0x0E ; DOS system call number for printing a single character
int 0x10 ; print high digit first. Doesn't clobber anything, so AH still holds 0x0E after
mov al, dl
int 0x10 ; print the low digit 2nd
ret
Так как мы использовали div
разделить целое на две base10 цифры, нам нужно ah
равным нулю. Мы могли бы сэкономить cbw
, если вызывающий абонент сделал movzx ax, ch
или что-то, до нуля ah
.
(За исключением того, что у 8086 не было movzx
, так что вы должны были бы на самом деле xor ax,ax
/mov al, ch
.)
Там в системном вызове DOS для печати целой строки, чтобы вы могли хранить символы в небольшой буфер и печатать их все сразу, как я в этом AMD64 Linux FizzBuzz
Это также возможного используйте aam
, чтобы разделить AL (вместо AX) на 10, избегая при этом необходимости нуля AH. Это немного быстрее, чем div r8
на современных процессорах Intel и AMD. Однако он помещает результаты в противоположные регистры от div
, что означает дополнительные инструкции после aam
. Это балансирует экономию на mov dl, 10
и cbw
print2Digits:
;; input in AL (0-99). (Ignores AH because we use AAM instead of div)
;; clobbers AX and DX
aam ; like `div` by 10, but with the outputs reversed, and input from AL only
; quotient in AH (high digit), remainder in AL(low digit). (Opposite to div)
add ax, 0x3030 ; add '0' to al and ah at the same time.
mov dl, al ; save the low digit
mov al, ah ; print high digit first
mov ah, 0x0E ; DOS system call number for printing a single character
int 0x10 ; print first digit. Doesn't clobber anything, so AH still holds 0x0E after
mov al, dl
int 0x10 ; print second digit
ret
Даже если мы хотели сохранить в строку (и сделать один вызов функции печати строки или системного вызова), мы должны были бы поменять местами Аль и ah перед хранением AX в памяти (например, xchg al,ah
, или более эффективно на современном оборудовании, rol ax,8
). div
производит их в правильном порядке.
Для 386, где 32-битный адрес, размер доступен, мы можем сохранить одну команду:
lea dx, [eax + 0x3030] ; need a 32bit addressing mode to use eax as a source reg. Adds '0' to both digits at once, with a different destination.
mov al, dh
lea
нужен префикс адреса размера и 2-байтовый мод/гт, и 32-битное смещение, поэтому он плохо проигрывает по размеру кода, но сохраняет одну инструкцию.
Использование lea
для чтения из eax
после div
пишет ax
, вероятно, будет быстрее на SandyBridge семейства процессоров, особ. Хасуэлл и позже, но на Intel pre-SnB, частичный регистрационный стойло позволит лучше использовать чистую 16-битную версию с отдельными инструкциями add и mov.
было ли это 2:14:02? :) – hobbs
да как я могу получить результат в цифрах? : s –
Я добавил emu8086 в теги, учитывая, что выведенный вами вывод экрана для этого эмулятора. –