Глава 17 - практика: ввод чисел и системы счисления
Мы используем cookie-файлы, чтобы получить статистику, которая помогает нам улучшить сервис для Вас с целью персонализации сервисов и предложений. Вы можете прочитать подробнее о cookie-файлах или изменить настройки браузера. Продолжая пользоваться сайтом без изменения настроек, вы даёте согласие на использование ваших cookie-файлов.
speech bubble

Глава 17 - практика: ввод чисел и системы счисления

Самоучитель по языку ассемблер(assembler)

Содержание:

 

ВНИМАНИЕ! Данный самоучитель был написан много лет назад и его автор не сможет ответить на ваши вопросы. Курс по assembler предназначен для саморазвития. Если у вас хватает квалификации, можете предложить внести правки.

 

Ввод чисел

Ввод числовой информации в ассемблерную программу обычно осуществляется в два этапа:

  1. ввод строки содержащей число
  2. перевод строки в число

Ввод строк рассматривался в предыдущих практических работах.

Для разработки алгоритма перевода введенной строки в число проанализируем структуру числа в позиционной системе счисления (в такой системе счисления вес цифры определяется ее местоположением в числе):

2398 = 2 * 1000 + 3 * 100 + 9 * 10 + 8 = 2 * 103 + 3 * 102 + 9 * 101 + 8 * 100

Таким образом, для перевода строки в число из введенной строки «2398» необходимо последовательно выделять цифры и производить суммирование произведений этих цифр и множителей соответствующих позиции цифры в числе. Если буфер для ввода строки был организован, например, следующим образом:

BUF 05, 00, 05 DUP (?)

то после ввода строки «2398» он будет выглядеть (в шестнадцатеричной системе счисления) так:

05, 04, 32, 33, 39, 38, 0d

где первый байт – размер буфера, второй – количество введенных символов (без завершающего символа CR), третий, четвертый, пятый, шестой и седьмой – коды символов «2», «3», «9», «8» и «CR» соответственно. Легко заметить, что для того, чтобы из кода цифры получить саму цифру необходимо из соответствующего кода вычесть 30h (шестнадцатеричный код нуля). Затем, последовательно в цикле (второй байт – количество введенных символов) выбирая цифры, формировать соответствующий множитель, вычислять произведение и производить суммирование. Нижеследующий фрагмент программы иллюстрирует описанный алгоритм (символы рассматриваются справа налево).

;Ввод числа в виде строки
MOV AH,0AH ;в AH номер функции
LEA DX, BUF ;DS:DX адрес буфера для ввода
INT 21H
;Перевод строки в число, результат в DI
MOV DI,0
LEA BX, BUF+1 ;в BX адрес второго элемента буфера
MOV CX,[BX] ;в CX количество введенных символов
XOR CH,CH
MOV SI,1 ;в SI множитель
MET: PUSH SI ;сохраняем SI (множитель) в стеке
MOV SI,CX ;в SI помещаем номер текущего символа
MOV AX,[BX+SI];в AX помещаем текущий символ
XOR AH,AH
POP SI ;извлекаем множитель (SI)из стека
SUB AX,30H ;получаем из символа (AX) цифру
MUL SI ;умножаем цифру (AX)на множитель (SI)
ADD DI,AX ;складываем с результирующим числом
MOV AX,SI ;помещаем множитель (SI) в AX
MOV DX,10
MUL DX ;увеличиваем множитель (AX) в 10 раз
MOV SI,AX ;перемещаем множитель (AX) назад в SI
LOOP MET ;переходим к предыдущему символу

 

Перевод чисел в различные системы счисления

В большинстве случаев перевод из одной системы счисления в другую осуществляется последовательным делением, в нашем случае, при переводе из десятичной системы счисления в двоичную, восьмеричную и шестнадцатеричную алгоритм можно значительно упростить, заменив деление сдвигом.

Перевод из десятичной системы счисления в двоичную осуществляется последовательными сдвигами на один бит вправо. Таким образом, значение очередного бита можно вычислить, проанализировав флаг переноса CF (если CF=1 то анализируемый бит был равен 1, и если CF=0, то анализируемый бит – 0).

Перевод из десятичной системы счисления в восьмеричную осуществляется последовательными сдвигами на три бита вправо. После очередного сдвига все биты кроме трех младших обнуляются (например, наложением маски командой AND). Таким образом, в регистре получается восьмеричная цифра, для получения ее символьного отображения к значению в регистре необходимо прибавить код нуля (30h).

Перевод из десятичной системы счисления в шестнадцатеричную осуществляется последовательными сдвигами на четыре бита вправо. После обнуления всех битов кроме четырех младших в регистре получается десятичный эквивалент шестнадцатеричной цифры (число от 0 до 15).

Для его представления в шестнадцатеричной символьной форме необходимо организовать таблицу соответствия, которая в простейшем случае представляет собой следующую строку «0123456789ABCDEF». При перекодировании значение десятичного эквивалента используется как смещение в таблице относительно ее начала (перекодировка может осуществляться при помощи команды XLAT).

Разбор программы

Задание: разработать программу перевода чисел из десятичной системы счисления в двоичную, восьмеричную и шестнадцатеричную. Числа должны вводиться в десятичной системе счисления, а выводятся – в двоичной, восьмеричной и шестнадцатеричной.

Программа получилась большая! кроме всего прочего в ней показано как работать с файлами в DOS, а также показано как описывать процедуры, сама по себе программа очень простая, всё понятно из комментариев. Работу с файлами мы рассмотрим далее, а здесь она только для примера.

Файл perevod.asm

.model tiny
.code
org 100h
start:
;выводим приглашение
mov dx,offset message3
mov ah,09h
int 21h
;вводим имя файла
mov ah,0Ah
mov dx,offset filename
int 21h
;получаем имя в буфере
mov si,2
mov di,0
mov cl, byte ptr [filename+1]
mov ch,0
lo:mov ah,filename[si]
mov buf[di],ah
inc di
inc si
loop lo
;перевод строки
mov dx,offset crlf
mov ah,09h
int 21h
call openfile;открываем файл
mov handle,ax
;выводим приглашение
mov dx,offset message1
mov ah,09h
int 21h
;вводим строку
mov ah,0Ah
mov dx,offset buffer
int 21h
;перевод строки
mov dx,offset crlf
mov ah,09h
int 21h
;перевод строки в число в регистре AX
xor di,di
xor ax,ax;ax текущее значение результата
mov cl,blen
xor ch,ch
xor bx,bx
mov si,cx;тут длина буфера
mov cl,10;тут множитель 10,для команды MUL
asc2bin:
mov bl,byte ptr bcontents[di]
sub bl,'0';вычитаем из цифры код нуля
jb ascer;если код цифры меньше чем код '0'
cmp bl,9;или больше чем код '9'
ja ascer
mul cx
add ax,bx
inc di
cmp di,si;продолжать пока счетчик+1 меньше числа символов
jb asc2bin
;теперь число расположено в регистре ax
inc ax;действие над числом (ну произвольное, для примера :))
;начинаем вывод числа в hex формате
push ax
mov ah,9
mov dx,offset message2
int 21h
pop ax
push ax
mov si,0;это позиция в буфере который будем писать в файл
mov buf2out[si],'H'
inc si
mov buf2out[si],'E'
inc si
mov buf2out[si],'X'
inc si
mov buf2out[si],' '
inc si
mov bx,ax;теперь в bx число для вывода в dec формате
xchg ah,al;поместить в al старший байт
call print_al_hex
pop ax;восстановить в al младший байт
call print_al_hex
;начинаем вывод числа в dec формате
mov dx,offset crlf
mov ah,09h
int 21h
mov ah,9
mov dx,offset message4
int 21h
mov ax,bx
call print_al_dec
;пишем в файл
mov ah,40h
mov bx,handle
mov cx,si
lea dx,buf2out
int 21h
mov ah,3eh
mov bx,handle
int 21h
;конец программы
ret
ascer:
mov dx,offset errms
mov ah,9
int 21h
ret
;процедура вывода числа в al в hex формате
print_al_hex:
mov dh,al
and dh,0Fh;младшие 4 бита в dh
shr al,4 ;старшие 4 бита в al
call print
mov al,dh;теперь здесь младшие 4 бита
print:
cmp al,10;эти три команды переведут цифру в al в код ASCII, так круче чем XLAT!
sbb al,69h
das
mov dl,al
mov buf2out[si],dl
inc si
mov ah,2
int 21h
ret;этот ret работает два раза
;процедура вывода числа в ax в dec формате
print_al_dec:
mov buf2out[si],0Dh
inc si
mov buf2out[si],0Ah
inc si
mov buf2out[si],'D'
inc si
mov buf2out[si],'E'
inc si
mov buf2out[si],'C'
inc si
mov buf2out[si],' '
inc si
mov cx,10
xor bx,bx
m1:cmp ax,10
jb m2
xor dx,dx
div cx
or dl,30h
push dx
inc bx
jmp m1
m2:or al,30h
push ax
inc bx
mov cx,bx
lop:pop dx
mov buf2out[si],dl
inc si
mov ah,2
int 21h
loop lop
ret
;процедура открытия файла - описатель в ax
openfile proc
mov ah,3ch
mov cx,0
mov dx,offset buf
int 21h
jnc nerr
mov dx,offset myerr
mov ah,9
int 21h
;перевод строки
mov dx,offset crlf
mov ah,09h
int 21h
nerr: ret
endp
;!!!!!!!!!!!!!!!!!!!!!!!!!ОПИСАНИЕ ДАННЫХ ПРОГРАММЫ!!!!!!!!!!!!!!!!!!!!!!!!!!!
handle dw ?;это описатель файла!
buf db 8 dup (0),0
;это буфер который мы запишем в файл!
buf2out db 20 dup (?),'$'
message1 db "Decimal number: $"
message2 db "Heximal number: $"
message4 db "New dec number: $"
message3 db "Enter file name: $"
filename db 9,?,9 dup (0),0
errms db "Error number:programm terminate!!!!!!!!!!!!!$"
myerr db "WARNING!!! File not create$"
crlf db 0Dh,0Ah,'$'
buffer db 6;максимальный размер для ввода числа
blen db ?;размер после ввода
bcontents: ;содержимое буфера числа за концом программы COM
end start

Компиляция:

c:\specprog\tasm\bin\tasm.exe perevod.asm
c:\specprog\tasm\bin\tlink.exe perevod.obj /t/x

Вот что получилось в результате:

 

Для комментирования необходимо авторизоваться