Как вывести число на экран и заснуть на одну секунду с 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

Я не уверен, как вывести значение топора на экран и как подождать 1 секунду (поместил их в комментарий в коде).


person Jean Carlos Suárez Marranzini    schedule 02.04.2012    source источник
comment
@PavanManjunath Да, я делаю это на ПК. Виндовс 7, 32 бита.   -  person Jean Carlos Suárez Marranzini    schedule 02.04.2012
comment
Что касается задержки, вы можете ознакомиться с последним сообщением в этой теме. Тактовая частота предполагается равной 100 МГц. Но вам нужно выяснить точное значение на вашей машине методом проб и ошибок. Эта ссылка также должна помогите разобраться с задержкой   -  person Pavan Manjunath    schedule 02.04.2012
comment
@PavanManjunath Я проверяю ссылки, они действительно интересны, большое спасибо. Я постараюсь понять, потому что я еще не очень хорошо разбираюсь в программировании на ассемблере. Будем очень признательны за любую другую помощь или ответ на этот вопрос.   -  person Jean Carlos Suárez Marranzini    schedule 02.04.2012


Ответы (1)


Существует 4-байтовый счетчик в сегменте 0 со смещением 46Ch (или, альтернативно, в сегменте 40h, offs 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, где находится вышеупомянутый счетчик.

person Alexey Frunze    schedule 02.04.2012
comment
Этот комментарий предназначен для @Alex. Он отлично работает, большое спасибо за вашу щедрую помощь. Я обязательно прочитаю все, что вы сказали в комментарии выше. Только один вопрос: сложно ли изменить код, который вы разместили, чтобы процесс пошел в обратном направлении? (от 255 до 0). - person Jean Carlos Suárez Marranzini; 02.04.2012
comment
Это тривиально/просто как в случае с div, так и с daa. - person Alexey Frunze; 02.04.2012
comment
PIT и даже RTC — другие варианты, если эти вещи работают в DOS. - person Ciro Santilli 新疆再教育营六四事件ۍ 07.11.2015
comment
Также не забывайте, что вам нужно sti, если вы ранее очищали cli. - person Ciro Santilli 新疆再教育营六四事件ۍ 07.05.2018