NASM - The Netwide Assembler
NASM Forum => Example Code => Topic started by: sledge on August 23, 2011, 02:56:11 AM
-
org 100h
mov ah, 9
mov dx, str1
int 21h
mov ah, 1
int 21h
mov ah, 9
cmp al, 37h
jz age_same
jg age_older
jl age_younger
jmp after
age_same:
mov dx, str2
int 21h
jmp after
age_older:
mov dx, str3
int 21h
jmp after
age_younger:
mov dx, str4
int 21h
jmp after
after:
mov ah, 4Ch
int 21h
str1 db 'ENTER YOUR AGE: $'
str2 db 0Ah, 'Wow. You and I are the same age.$'
str3 db 0Ah, 'You are older than me, pal. Cool!$'
str4 db 0Ah, 'I am older than you, haha!$s'
This wonderful program asks for your age, compare and then outputs a message based on how old you claimed to be.
Problem is I can't type more than one character... so in this program you cant be older than 9 years old.
-
I see one serious error:
str4 db 0Ah, 'I am older than you, haha!$s'
Should be:
str4 db 0Ah, 'I am older than you, groan!$'
Seriously, is there a question in this? Do you want to be older than 9? (answer carefully - it doesn't stop at 9!) :)
If you want to be able to enter a multi-digit number, that can be arranged. You could either enter a string (int 21h/0Ah or int 21h/0C0Ah or maybe the "file read" interrupt on stdin...) and "convert" it to a number. Or, you could get input character-by-character as you're doing and "convert" to a number as you go along. I'd use a "no echo" input (int 21h/7 or int 21h/8 IIRC), and echo it only if it's a valid digit - maybe beep otherwise (char 07h). In either case:
; set a "result so far" to zero
; get a character (from keyboard or "string")
; if it's EOS, quit
; check that it's a valid decimal digit
; if not... display error? quit?
; multiply the "result so far" by ten
; convert the character to a number
; add it to "result so far"
Here's a "clever" (IMO) method which uses "lea" a couple times to multiply by ten, "convert" the character, and add it in. This is intended for 32-bit code, and expects the address of a string on the stack. It could probably be altered to work in 16-bit code, although you'd need to keep the 32-bit addressing modes... probably easier to just multiply by ten with "mul" in 16-bit code. It takes any non-digit as EOS, and doesn't check for overflow. It handles only unsigned (positive) numbers. You probably won't get any negative ages (although them pesky "users" will type in any darn thing - gotta watch 'em!). It illustrates the general idea...
atoi:
mov edx, [esp + 4] ; pointer to string
xor eax, eax ; clear "result"
.top:
movzx ecx, byte [edx]
inc edx
cmp ecx, byte '0'
jb .done
cmp ecx, byte '9'
ja .done
; we have a valid character - multiply
; result-so-far by 10, subtract '0'
; from the character to convert it to
; a number, and add it to result.
lea eax, [eax + eax * 4]
lea eax, [eax * 2 + ecx - 48]
jmp short .top
.done
ret
Your "jg" and "jl" are for signed numbers - "ja" and "jb" for unsigned. Unless someone claims to be very old, a signed number won't be interpreted as negative, so it shouldn't cause a problem...
Best,
Frank
-
; avch. You can input 2 characters, do not checking errors
MyAge EQU 38
[org 100h]
[section .text]
mov dx, Text1
mov ah, 9
int 21h
mov dx, Input
mov ah, 0Ah
int 21h
mov si, Input+1
xor bh, bh
cmp byte [Input+1], 1
mov bl, byte [Input+2]
jz @next
mov bx, word [Input+2]
@next:
xor ah, ah
mov al, bl
and al, 0Fh
mov cl, 10
mul cl
mov ah, bh
and ah, 0Fh
add al, ah
cmp al, MyAge
mov di, Text4 + 2 ; Let's suppose are equal
ja @Above
jb @Below
jmp @Next2
@Above:
mov di, Text3 + 2
jmp @Next2
@Below:
mov di, Text2 + 2
@Next2:
mov ax, bx
stosw
sub di, 4
mov dx, di
mov ah, 9
int 21h
ret
[section .data]
Input db 3, " "
Text1 db "How old are you?: $"
Text2 db 13, 10, " and you're not lying yet?$"
Text3 db 13, 10, " , take a soup and go to bed!$"
Text4 db 13, 10, " , What good vintage!$"
Greetings
-
Didnt know there were more functions (in int 21h) that worked with user input, thought 1h was the only one, good to know, I'll try them out. I'm sorry if this is too obvious, but what do you mean by "I'd use a no echo input", I tried googling for echo but didnt find the meaning of this term when it comes to programming.
-
"Echo" just indicates whether the character is displayed on the screen or not.
http://www.ctyme.com/intr/int-21.htm
Compare ah=1 with ah=7 or 8. Check out ah=6 while you're there - kind of an "interesting" one. The bios int 16h can also be used.
If you're not familiar with "Ralf Brown's Interrupt List"...
http://www.cs.cmu.edu/~ralf/files.html
Ralf's your new best friend! Besides the actual "interrupt list", there's info on ports, memory, instructions... Almost "necessary" if you're going to mess with dos, and quite useful even if you're not!
The idea behind "no echo" input is to not even display the character if the user enters a "non-digit" - saves having to mess with "backspace". :)
By all means, try stuff out. "Learning dos" is not that useful these days, but it's good experience writing asm, and it's "fun" (a matter of opinion, I suppose...)
Best,
Frank
-
Int 21h has many more than 1h function, for almost everything you need. Also, there is not only Int 21h interrupt. As Frank says, Ralf Brown's Interrupt List would be a good friend.
Regarding MS-DOS programming I think it is a clever task. I believe that, in the core, is not very different from Windows programming. One gives you interrupts to programming and other functions, but basically are the same. Moreover, if you learn DOS programming, I guess you can do it also in Windows without great difficulty. Besides, I think it is a pity losing decades of programming experience. That's at least my opinion.
Well, since we have the code above, I present the secret number guessing game. Indeed, this code fixes a small mistake in the previous one, of what no one seemed to have noticed.
; avch. Guess the secret number. Random routine need to be improved, but it should work
; hit CTRL+C at any time to exit
[org 100h]
[section .text]
xor ah, ah
int 1ah
mov word [RandSeed], dx
@main:
mov cx, 30
call Random
inc dx
mov byte [Secret], dl
xor ah, ah
mov al, dl
mov cl, 10
div cl
or ax, 3030h
mov word [Text3+17], ax ; The secret number in final text
mov cl, 5
@Inner:
mov ch, cl
or ch, 30h
mov byte [Text1+27], ch ; Attempts left in input text
; Input message
mov dx, Text1
mov ah, 9
int 21h
; Get Response
mov dx, Input
mov ah, 0Ah
int 21h
call GetResp
call Success
jc @Exit
jnz @Inner
@Exit:
; ¿Exit?
mov dx, Text4
mov ah, 9
int 21h
xor ah, ah
int 16h
or al, 100000b
cmp al, 'y'
jz @main
mov dx, Text5
mov ah, 9
int 21h
ret
Success:
clc ; There are attempts, mark it
cmp al, byte [Secret] ; Are we success?
mov dx, Text2 ; we suppose so
jz @SExit
cmp cl, 1
ja @Next1
; We have finished attempts
mov dx, Text3 ; We have finished, failed
stc ; Mark it
jmp @SExit
@Next1:
; We have not finished yet and we have not succeeded
dec cl ; One attempt less
sub al, byte [Secret] ; Which is greather?
mov dx, Text6 ; Suppose lower
js @SExit0
mov dx, Text7 ; no, greather
@SExit0:
clc ; There are attempts, mark it
@SExit:
; Print the message
mov ah, 9
int 21h
ret
Random:
; Purpose : pseudo random number in [0, CL)
; In : CX
; Out : DL: número aleatorio
; Destoys : DX
push ax
mov ax, [RandSeed]
mov dx, 8405h
mul dx
inc ax
mov [RandSeed],ax
xor dx, dx
div cx
pop ax
ret
GetResp:
; Out : al
push bx
push cx
push si
mov si, Input+1
xor bh, bh
cmp byte [Input+1], 1
mov bh, byte [Input+2]
jz @next
mov bx, word [Input+2]
@next:
xor ah, ah
mov al, bl
and al, 0Fh
mov cl, 10
mul cl
mov ah, bh
and ah, 0Fh
add al, ah
pop si
pop cx
pop bx
ret
[section .bss]
RandSeed resw 1
Secret resb 1
[section .data]
Input db 3, " "
Text1 db 13, 10, "Guess the number [1,30], attempts: $"
Text2 db 13, 10, "Right!", 13, 10, "$"
Text3 db 13, 10, "Failed, it was ", 13, 10, "$"
Text4 db 13, 10, "Try again (Y/N)?$"
Text5 db 13, 10, 13, 10, "Take a look at http://www.abreojosensamblador.net/", 13, 10, "bye!$"
Text6 db 13, 10, "Too low", 13, 10, "$"
Text7 db 13, 10, "Too high", 13, 10, "$"
Cheers!