; (c) xrnd [2010] [http://asmworld.ru/]
; printdec.asm - вывод чисел в десятичном виде (со знаком и без знака)

use16			    ;Генерировать 16-битный код
org 100h		    ;Программа начинается с адреса 100h

    mov ax,0xA83D	    ;Число, которое будем выводить
    mov cx,print_str	    ;Адрес процедуры print_str
    mov bx,print_endline    ;Адрес процедуры print_endline

    mov di,s_ubyte
    call cx		    ;Вывод строки 'unsigned byte:'
    call print_byte_udec    ;Вывод AL в десятичном виде (без знака)
    call bx		    ;Вывод конца строки
    mov di,s_uword
    call cx		    ;Вывод строки 'unsigned word:'
    call print_word_udec    ;Вывод AX в десятичном виде (без знака)
    call bx		    ;Вывод конца строки
    mov di,s_sbyte
    call cx		    ;Вывод строки 'signed byte  :'
    call print_byte_sdec    ;Вывод AL в десятичном виде (со знаком)
    call bx		    ;Вывод конца строки
    mov di,s_sword
    call cx		    ;Вывод строки 'signed word  :'
    call print_word_sdec    ;Вывод AX в десятичном виде (со знаком)
    call bx		    ;Вывод конца строки

    mov di,s_pak
    call cx		    ;Вывод строки 'Press any key...'
    mov ah,8		    ;Функция DOS 08h - ввод символа без эха
    int 21h

    mov ax,4C00h	    ;\
    int 21h		    ;/ Завершение программы

;----------------------------------------------------------------------
;Процедура вывода байта на консоль в десятичном виде (без знака)
; AL - байт
print_byte_udec:
    push di
    mov di,buffer	    ;DI = адрес буфера
    push di		    ;Сохранение DI в стеке
    call byte_to_udec_str   ;Преобразование байта в AL в строку
    mov byte[di],'$'	    ;Добавление символа конца строки
    pop di		    ;DI = адрес начала строки
    call print_str	    ;Вывод строки на консоль
    pop di
    ret

;----------------------------------------------------------------------
;Процедура вывода слова на консоль в десятичном виде (без знака)
; AX - слово
print_word_udec:
    push di
    mov di,buffer	    ;DI = адрес буфера
    push di		    ;Сохранение DI в стеке
    call word_to_udec_str   ;Преобразование слова в AX в строку
    mov byte[di],'$'	    ;Добавление символа конца строки
    pop di		    ;DI = адрес начала строки
    call print_str	    ;Вывод строки на консоль
    pop di
    ret

;----------------------------------------------------------------------
;Процедура вывода байта на консоль в десятичном виде (со знаком)
; AL - байт
print_byte_sdec:
    push di
    mov di,buffer	    ;DI = адрес буфера
    push di		    ;Сохранение DI в стеке
    call byte_to_sdec_str   ;Преобразование байта в AL в строку
    mov byte[di],'$'	    ;Добавление символа конца строки
    pop di		    ;DI = адрес начала строки
    call print_str	    ;Вывод строки на консоль
    pop di
    ret

;----------------------------------------------------------------------
;Процедура вывода слова на консоль в десятичном виде (со знаком)
; AX - слово
print_word_sdec:
    push di
    mov di,buffer	    ;DI = адрес буфера
    push di		    ;Сохранение DI в стеке
    call word_to_sdec_str   ;Преобразование слова в AX в строку
    mov byte[di],'$'	    ;Добавление символа конца строки
    pop di		    ;DI = адрес начала строки
    call print_str	    ;Вывод строки на консоль
    pop di
    ret

;----------------------------------------------------------------------
;Процедура вывода строки на консоль
; DI - адрес строки
print_str:
    push ax
    mov ah,9		    ;Функция DOS 09h - вывод строки
    xchg dx,di		    ;Обмен значениями DX и DI
    int 21h		    ;Обращение к функции DOS
    xchg dx,di		    ;Обмен значениями DX и DI
    pop ax
    ret

;----------------------------------------------------------------------
;Процедура вывода конца строки (CR+LF)
print_endline:
    push di
    mov di,endline	    ;DI = адрес строки с символами CR,LF
    call print_str	    ;Вывод строки на консоль
    pop di
    ret

;----------------------------------------------------------------------
;Процедура преобразования байта в строку в десятичном виде (без знака)
; AL - байт.
; DI - буфер для строки (3 символа). Значение регистра не сохраняется.
byte_to_udec_str:
    push ax
    xor ah,ah		    ;Преобразование байта в слово (без знака)
    call word_to_udec_str   ;Вызов процедуры для слова без знака
    pop ax
    ret

;----------------------------------------------------------------------
;Процедура преобразования слова в строку в десятичном виде (без знака)
; AX - слово
; DI - буфер для строки (5 символов). Значение регистра не сохраняется.
word_to_udec_str:
    push ax
    push cx
    push dx
    push bx
    xor cx,cx		    ;Обнуление CX
    mov bx,10		    ;В BX делитель (10 для десятичной системы)

wtuds_lp1:		    ;Цикл получения остатков от деления
    xor dx,dx		    ;Обнуление старшей части двойного слова
    div bx		    ;Деление AX=(DX:AX)/BX, остаток в DX
    add dl,'0'		    ;Преобразование остатка в код символа
    push dx		    ;Сохранение в стеке
    inc cx		    ;Увеличение счетчика символов
    test ax,ax		    ;Проверка AX
    jnz wtuds_lp1	    ;Переход к началу цикла, если частное не 0.

wtuds_lp2:		    ;Цикл извлечения символов из стека
    pop dx		    ;Восстановление символа из стека
    mov [di],dl 	    ;Сохранение символа в буфере
    inc di		    ;Инкремент адреса буфера
    loop wtuds_lp2	    ;Команда цикла

    pop bx
    pop dx
    pop cx
    pop ax
    ret

;----------------------------------------------------------------------
;Процедура преобразования байта в строку в десятичном виде (со знаком)
; AL - байт.
; DI - буфер для строки (4 символа). Значение регистра не сохраняется.
byte_to_sdec_str:
    push ax
    movsx ax,al 	    ;Преобразование байта в слово (со знаком)
    call word_to_sdec_str   ;Вызов процедуры для слова со знаком
    pop ax
    ret

;----------------------------------------------------------------------
;Процедура преобразования слова в строку в десятичном виде (со знаком)
; AX - слово
; DI - буфер для строки (6 символов). Значение регистра не сохраняется.
word_to_sdec_str:
    push ax
    test ax,ax		    ;Проверка знака AX
    jns wtsds_no_sign	    ;Если >= 0, преобразуем как беззнаковое
    mov byte[di],'-'	    ;Добавление знака в начало строки
    inc di		    ;Инкремент DI
    neg ax		    ;Изменение знака значения AX
wtsds_no_sign:
    call word_to_udec_str   ;Преобразование беззнакового значения
    pop ax
    ret

;---------------------------------------------------------------------
; Данные
s_ubyte  db 'unsigned byte: $'
s_uword  db 'unsigned word: $'
s_sbyte  db 'signed byte  : $'
s_sword  db 'signed word  : $'
s_pak	 db 'Press any key...$'
endline  db 13,10,'$'
buffer	 rb 7
