I'm using NASM 16 BITS. I'm trying to do a simple assembly code that prints the numbers from 0 to 255 with 1 second interval between each number. This is what I have so far:
[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
I'm not sure how to print the value of ax in the screen, and how to wait 1 second(placed them in a comment in the code).
There's a 4-byte counter at segment 0 offset 46Ch (or alternatively at seg 40h, offs 6Ch) maintained and updated by the PC BIOS. It's incremented 18.2 times per second. Counting 18 changes in the lowest byte or word of this counter is probably the simplest way of waiting out approximately a second:
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
To print decimal numbers you need to convert binary numbers into decimal, get individual digits and print them. You divide the number by 10 and collect remainders. e.g.:
123:
123 / 10: quotient 12, remainder 3
12 / 10: quotient 1, remainder 2
1 / 10: quotient 0, remainder 1
By repeatedly dividing by 10 you get the individual digits in the remainders in the reverse order: 3,2,1. Then you print them using DOS int 21h function 2 (load 2 into AH
, load the character's ASCII code into DL
, execute int 21h
).
An alternative variant, quite suited to your problem, would be to use the DAA
instruction to increment the number directly in decimal without any conversion.
Here's how it all can be done:
; 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,"$"
If you don't like the leading zeroes or the last 1-second delay, you can conditionally skip them.
Download Intel and/or AMD x86 CPU manuals that describe how each instruction works. Read them. Also, download the Ralf Brown's Interrupt List
, which describes every BIOS and DOS function. You need to know some of them to do I/O. There are also HelpPC
and TechHelp
that conveniently describe many BIOS and DOS things like the BIOS Data Area
where the aforementioned counter lives.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With