I am trying to write an assembly program to display even numbers starting from 0 to I where I is supplied by the user. I'm trying to use the following code:
.model small
.stack
code segment
assume cs:code
_start:
mov ah, 1h
int 21h
mov dl, al
mov ah, 2h
myloop:
sub dl, 2
mov ah, 2h
int 21h
cmp dl, 0
jge myloop
mov ah, 4ch
int 21h
code ends
end _start
However, I'm facing several problems.
I can only get a single character input
I can't really convert the supplied input to integer (it seems to be an ascii character); subtracting 48 from input wouldn't work because the user can want to start from 100
I only want to display numbers as output not the whole ascii characters starting from input
Thanks!
One easy way to get an input string from the user is the Buffered Input function:
http://www.ctyme.com/intr/rb-2563.htm
To do the conversion from an ASCII string to an integer value, a rough description in some fairly-crappy pseudo code:
value = 0
starting at first char of string:
for each char
if char is digit
digitvalue = char - 30h
value = value * 10
value = value + digitvalue
else
if at end of string
done
else
invalid char in string
endif
endif
end for
You may want to code the conversion to handle a leading sign, or to ignore leading zeros. And an easy way to handle invalid (non-digit) characters is to just stop the conversion at the first invalid character, and assume that you have reached the end of the string.
is this what you mean ?
(i already had the routines written for another program :P )
Wow, thanks so much @dedndave! I guess the lines I really need are:
;display even numbers from 0 to <UserValue>
mov bx,dx
xor ax,ax
Evens0: call UnsDec
call StrOut
add ax,2
jc Exit00
cmp ax,bx
jbe Evens0
However, jc
and xor
are new to me, can you explain to me properly what happens there?
Thanks.
Also when I try to compile this using masm32 qeditor, it gives me the following errors:
QuoteAssembling: C:\masm32\even.asm
C:\masm32\even.asm(5) : warning A4015: directive ignored with /coff switch
C:\masm32\even.asm(55) : error A2006: undefined symbol : DGROUP
C:\masm32\even.asm(57) : error A2006: undefined symbol : DGROUP
C:\masm32\even.asm(64) : error A2074: cannot access label through segment registers
C:\masm32\even.asm(185) : error A2074: cannot access label through segment registers
NOTE: I'm running win7 x64, and I've seen this error with other programs, so I guess it's not peculiar to this one.
Do you know why this is happening?
well - if they enter the value 65535, the thing will run endlessly :P
so, to prevent that, i put in a JC instruction (jump if carry)
if adding 2 to the register causes it to rollover, or overflow, i exit the loop
XOR is used in many ways - in this case, it is a shortcut method of setting a register to 0
this recent thread has some related discussion...
http://www.masm32.com/board/index.php?topic=18543.0
1) you shouldn't be using the /COFF switch for 16-bit programs
2) you should use the 16-bit linker for 16-bit programs (link16.exe) instead of the 32-bit linker
3) i dunno how that program works for you, as 16-bit programs aren't supposed to run under 64-bit OS's :bg
here is the batch file i use to assemble and link 16-bit programs (a16.bat)...
@echo off
if "x%1"=="x" goto a16usage
if exist %1.asm goto a16asm
:a16usage
echo Usage: a16 asmfile
echo "asmfile" = asmfile.asm
goto batchexit
:a16asm
if exist %1.obj del %1.obj
c:\masm32\bin\ml /c /Fl %1.asm >c:\masm32\bin\asmbl.txt
if errorlevel 1 goto showtxt
if exist %1.exe del %1.exe
c:\masm32\bin\Link563 /MAP %1.obj; >>c:\masm32\bin\asmbl.txt
:showtxt
if exist %1.obj del %1.obj
type c:\masm32\bin\asmbl.txt
:batchexit
dir %1.* /o-d
Okay, thanks, I changed the Link563 in your assembly code to link16 and it now works fine :)
I'm using DosBox (http://www.dosbox.com/) to run my codes :)
Also, do you have any idea of how I can change the settings of the qeditor masm32 compiler or can these not be changed?
well - you don't want to change the ones he has in there
you will want them for when you do 32-bit code
but, i think you can add one to the list
create the a16 batch file as i show above and place it in the bin folder
then, have a look at the INI files for QE - i suspect you just add a line for it
lnk563 and link16 are more-or-less the same thing
however, lnk563 is a self-extracting zip file - a little confusing the first time you run it
because it wants to overwrite itself
Yeah, I get it now. Besides, since I have to use an emulator to run my code (I'm now using msdos (http://homepage3.nifty.com/takeda-toshiya/msdos/index.html) instead, supports more output on screen), I don't mind using only 2 lines (thanks to your batch code) to execute my programs in cmd.
Also in your code there's a line like this:
div bx ;divide DX:AX by 10
I hope I'm not sounding dumb/painful, but I really don't understand what's happening there. I will also like to have a link where I can learn what registers? like di means.
Thanks for your time.
well - that particular instruction does as the comment suggests
the BX register holds 10 throughout the loop, as i recall
so, it divides the 32-bit value in DX:AX by 10
the remainder will be in DX and the quotient will be in AX
http://www.arl.wustl.edu/~lockwood/class/cs306/books/artofasm/toc.html
http://www.arl.wustl.edu/~lockwood/class/cs306/books/artofasm/Chapter_6/CH06-1.html
Cool, thanks :8). I guess you're more correct. The link (http://www.arl.wustl.edu/~lockwood/class/cs306/books/artofasm/Chapter_6/CH06-2.html#HEADING2-451) has a tiny error:
QuoteIf the operand is a 16 bit quantity, then the div instruction divides the 32 bit quantity in dx:ax by the operand leaving the quotient in ax and the remainder in . With 32 bit operands (on the 80386 and later) div divides the 64 bit value in edx:eax by the operand leaving the quotient in eax and the remainder in edx.
Obviously it's missing dx after in?
yes, an error - never noticed that one - lol
I'm beginning to have a bit of a hard time. I'm trying to add some comments based on what I understand to the code myself.
PrInp1: lodsb ;get next character in dx and set in al
xor al,30h ;subtract 48 from this character
cmp al,9 ; with line below, checks if the character is above 9 after subtraction and jumps? does that if we have - 2 after subtraction what then?
ja PrInp2 ;
cmp dx,6553 ; Guess the choice of 6553 is random?
ja PrInp4
shl dx,1 ;I don't quite understand are you converting to byte by using 3 shl instructions (From what I read now that's equal to * 8) ? why not do it once if that's the case?
mov bx,dx
shl dx,1
shl dx,1
add dx,bx ; after multiplication by first 2 add multiplication by 4? 2 value?
add dx,ax ; can you help me with what ax will hold at this point?
jc PrInp4 ; if value is greater than the 8 byte limit jump???
loop PrInp1
pop ax ;discard string pointer
pop si ;restore registers
pop cx
pop bx
pop ax
ret
Pls check my comments for my understanding of your code. Thanks
PrInp1: lodsb ;same as MOV AL,[SI]/INC SI
xor al,30h ;convert ASCII numeric character to binary
cmp al,9 ;if the result is greater than 9,
ja PrInp2 ;then it wasn't an ASCII numeric character
cmp dx,6553 ;16-bit registers hold 65535 max
ja PrInp4 ;if above 6553, multiplying by 10 would be overflow
;here, we multiply the saved (accumulated) value by 10, then add the new binary digit
shl dx,1 ;DX = 2 X val
mov bx,dx ;BX = DX = 2 X val
shl dx,1 ;DX = 4 X val
shl dx,1 ;DX = 8 X val
add dx,bx ;(8 X val) + (2 X val) = 10 X val
add dx,ax ;add the new binary digit
jc PrInp4 ;if the result is greater than 65535, overflow
loop PrInp1 ;loop until done (same as DEC CX/JNZ PrInp1)
I think You tried to input just even numbers from keyboard in your code
using "DIV" is better way for it
.model small
.stack
.data
.code
start:
mov ax,@data
mov ds,ax
lp1:
mov ah, 1h
int 21h
cmp al,0Dh
je exit
cmp al,30h
jb go
cmp al,39h
ja go
mov bl,al
xor ah,ah
mov dl,2
div dl
cmp ah,0
jne go
mov dl,bl
mov ah,02h
int 21h
go:
mov dl,08h
mov ah,02h
int 21h
mov dl,00h
mov ah,02h
int 21h
mov dl,08h
mov ah,02h
int 21h
jmp lp1
exit:
mov ah, 4ch
int 21h
end start
Quote from: dedndave on March 21, 2012, 11:04:04 PM
PrInp1: lodsb ;same as MOV AL,[SI]/INC SI
xor al,30h ;convert ASCII numeric character to binary
cmp al,9 ;if the result is greater than 9,
ja PrInp2 ;then it wasn't an ASCII numeric character
cmp dx,6553 ;16-bit registers hold 65535 max
ja PrInp4 ;if above 6553, multiplying by 10 would be overflow
;here, we multiply the saved (accumulated) value by 10, then add the new binary digit
shl dx,1 ;DX = 2 X val
mov bx,dx ;BX = DX = 2 X val
shl dx,1 ;DX = 4 X val
shl dx,1 ;DX = 8 X val
add dx,bx ;(8 X val) + (2 X val) = 10 X val
add dx,ax ;add the new binary digit
jc PrInp4 ;if the result is greater than 65535, overflow
loop PrInp1 ;loop until done (same as DEC CX/JNZ PrInp1)
:eek Thanks, that was really very helpful. :bg I wonder how long it will really take me to understand asm language.
Quote from: Force on March 21, 2012, 11:10:09 PM
I think You tried to input just even numbers from keyboard in your code
using "DIV" is better way for it
.model small
.stack
.data
.code
start:
mov ax,@data
mov ds,ax
lp1:
mov ah, 1h
int 21h
cmp al,0Dh
je exit
cmp al,30h
jb go
cmp al,39h
ja go
mov bl,al
xor ah,ah
mov dl,2
div dl
cmp ah,0
jne go
mov dl,bl
mov ah,02h
int 21h
go:
mov dl,08h
mov ah,02h
int 21h
mov dl,00h
mov ah,02h
int 21h
mov dl,08h
mov ah,02h
int 21h
jmp lp1
exit:
mov ah, 4ch
int 21h
end start
@Force, thanks, the problem is not just receiving the inputs, after receiving the input I want to list even numbers from the supplied input to 0 or vice versa. If you could comment your code also, it will be very helpful. Thanks