Программирование на Ассемблере под DOS

А теперь, собственно, пропиваю саму


А теперь, собственно, пропиваю саму процедуру вместа с традиционным расжевыванием оной: ;-[write_decimal, v1]------------------------------------ ;печатает десятичное беззнаковое число ;на входе: dx - типа число ;на выходе: нихрена ;прерывания: ан нэту ;процедуры: write_hex_digit ;-------------------------------------------------------- write_decimal proc push ax push cx push dx push bx mov ax,dx ;(1) mov bx,10d ;(2) xor cx,cx ;(3) non_zero: xor dx,dx ;(4) div bx ;(5) push dx ;(6) inc cx ;(7) cmp ax,0 ;(8) jne non_zero write_digit_loop: pop dx ;(9) call write_hex_digit ;(10) loop write_digit_loop pop bx pop dx pop cx pop ax ret write_decimal endp
Алгоритм простой: пока частное не равно 0, делим его, делим и еще раз делим на 10d, запихивая остатки в стек. Потом - извлекаем из стека. Вот и вся "конвертация" из HEX в BIN :). Это если в двух словах.
  А если подробно, то вот что получается:
  Бряк 1 - подготавливаем делимое. Как уже говорилось, оно у нас задается неявно - обязательно через AX. А параметр у нас - через DX процедуре передается. Вот и перемещаем.
  Бряк 2 - это, собственно, делитель.
  Бряк 3 - очищаем CX. Он у нас будет в качестве счетчика. О нем мы еще поговорим.
  Бряк 4 - очищаем DX. Если не очистим, то мы не 1234h какое-нить на 10 делить будем, а 12341234h. Первое 1234 нам надо? Вот и я говорю - очищаем!
  Бряк 5 - делим! Частное - в AX, остаток - в DX.
  Бряк 6 - заносим остаток (DX) в стек ;).
  Бряк 7 - CX=CX+1. Это мы считаем сколько раз "щемили остаток", который "щемится", по кругу (прыжок на метку non_zero), пока AX не равно 0 (бряк 8). То есть делим, делим AX, пока он не окажется, что делить, собственно, нечего.
  Так-с... Деление закончено, число раз, которое мы поделили AX до его полного обнуления, хранится в CX.
  Дальше все просто. Нам нужно такое же количество раз (CX) извлечь значение (DX) из стека. И это будет "HEX", переведенный в DEC. (Оно же: число в двоично коде, разобранное на последовательность десятичных цифр).
  Помните, как у нас организуется цикл? Через loop и CX?
  Если бы в качестве счетчика мы использовали какой-нибудь другой регистр, то пришлось бы извращаться со всякими метками и прыжками... а так все просто, все продуманно :). Цикл, в теле которого ИЗВЛЕЧЬ ЦИФЕРКУ (бряк 9) и НАПЕЧАТАТЬ ЦИФЕРКУ (бряк 10). Столько же раз, сколько мы и делили наше исходное шестнадцатеричное число.

  Для тех, кто не понял: бряк - это брекпоинт. Для тех, кто еще не знает, что такое брекпоинт - ищите объяснение в 'DZebug. Руководство юZверя'

 

Содержание раздела