Как вывести число на экран и так и поспать одну секунду со сборкой DOS x86?
Я использую NASM 16 бит. Я пытаюсь сделать простой ассемблерный код, который печатает числа от 0 до 255 с интервалом в 1 секунду между каждым числом. Это то, что я до сих пор:
[bits 16]
mov ax,cs
mov ds,ax
mov cx,255
mov ax,0
myloop:
;print in screen ax value
;wait 1 second
inc ax
loop myloop
Я не уверен, как напечатать значение ax на экране и как ждать 1 секунду (поместил их в комментарии в коде).
1 ответ
Существует 4-байтовый счетчик в смещении сегмента 0 46Ch (или, альтернативно, в сегменте 40h, с 6Ch), который поддерживается и обновляется BIOS компьютера. Увеличивается в 18,2 раза в секунду. Подсчет 18 изменений в младшем байте или слове этого счетчика является, вероятно, самым простым способом ожидания примерно секунды:
mov ax, 0
mov ds, ax
mov cx, 18
mov bx, [46Ch]
WaitForAnotherChange:
NoChange:
mov ax, [46Ch]
cmp ax, bx
je NoChange
mov bx, ax
loop WaitForAnotherChange
Для печати десятичных чисел вам необходимо преобразовать двоичные числа в десятичные, получить отдельные цифры и распечатать их. Вы делите число на 10 и собираете остатки. например:
123:
123/10: частное 12, остаток 3
12/10: частное 1, остаток 2
1/10: частное 0, остаток 1
Повторяя деление на 10, вы получаете отдельные цифры в остатках в обратном порядке: 3,2,1. Затем вы печатаете их, используя DOS Int 21h функцию 2 (загрузить 2 в AH
загрузить код ASCII персонажа в DL
выполнить int 21h
).
Альтернативный вариант, вполне подходящий для вашей проблемы, будет использовать DAA
Инструкция для увеличения числа непосредственно в десятичном виде без преобразования.
Вот как это все можно сделать:
; file: counter.asm
; assemble: nasm.exe counter.asm -f bin -o counter.com
bits 16
org 0x100
mov ax, 0 ; initial number
mov cx, 256 ; how many numbers
NextNumber:
%if 1 ; change to 0 to use the DAA-based method
push ax
mov dx, 0
div word [ten]
push dx
mov dx, 0
div word [ten]
push dx
mov dx, 0
div word [ten]
push dx
pop dx
call PrintDigit
pop dx
call PrintDigit
pop dx
call PrintDigit
pop ax
call PrintNewLine
call Wait1s
inc ax
%else
mov dl, ah
call PrintDigit
mov dl, al
shr dl, 4
call PrintDigit
mov dl, al
and dl, 0Fh
call PrintDigit
call PrintNewLine
call Wait1s
add al, 1
daa
adc ah, 0
%endif
loop NextNumber
ret
PrintDigit:
pusha
mov ah, 2
add dl, '0'
int 21h
popa
ret
PrintNewLine:
pusha
mov dx, CRLF
mov ah, 9
int 21h
popa
ret
Wait1s:
pusha
push ds
mov ax, 0
mov ds, ax
mov cx, 18
mov bx, [46Ch]
WaitForAnotherChange:
NoChange:
mov ax, [46Ch]
cmp ax, bx
je NoChange
mov bx, ax
loop WaitForAnotherChange
pop ds
popa
ret
ten dw 10
CRLF db 13,10,"$"
Если вам не нравятся начальные нули или последняя 1-секундная задержка, вы можете их условно пропустить.
Загрузите руководства по процессорам Intel и / или AMD x86, в которых описано, как работает каждая инструкция. Читать их. Также скачайте Ralf Brown's Interrupt List
, который описывает все функции BIOS и DOS. Вы должны знать некоторые из них, чтобы сделать ввод / вывод. Это также HelpPC
а также TechHelp
которые удобно описывают многие вещи BIOS и DOS, такие как BIOS Data Area
где живет вышеупомянутый счетчик.