I'm trying to write a simple "while" in fasm that print A into DOS console 4 times. Here the code
org 100h
use16
jnp ciclo
ciclo:
cmp [c],0
jle fine
mov ah,02h
mov dl,'A'
int 21h
dec [c]
jnp ciclo
fine: ret
c db 5
When i run it it prints only one A on the scren and then exit.
Sameone can help?
Thanks
Gianluca
JNP is a conditional jump if the parity flag is not set. You want the unconditional jump (JMP) instead.
Related
I've been trying to get it to work for several hours now and nothing seems to make the output to come out in either one or two lines. I've taken the second loop I had before with a string, changed a's to b's and even switched the order little by little.
Code:
[org 0x7c00]
mov ah, 0x0e
mov bx, varName
printString:
mov al, [bx]
cmp al, 0
je end
int 0x10
inc bx
jmp printString
end:
jmp $
varName:
db "Hello World", 0
mov bh, 0x0e
mov bl, 'Z'
int 0x10
loop:
dec bl
cmp bl, 'A' - 1
je exit
int 0x10
jmp loop
exit:
jmp $
times 510-($-$$) db 0
dw 0xaa55
current output: Hello World
I tried removing both, one at a time, and it works as intended ran separately.
Note: I'm using qemu, asm, vim and have been using vscode to help with any writing misspellings
changed a's to b's
Don't do this! If an api states that it expects the function number in the AH register, then it will surely not help to try passing it in the BH register.
In a sense you got lucky with that jmp $ not letting you execute that bogus second part.
To execute both parts of the code, you could replace that jmp $ (which is an endless loop), with a normal jump to the first instruction of the second part:
...
end:
jmp Part2
varName:
db "Hello World", 0
Part2:
mov ah, 0x0E ; BIOS.Teletype
mov al, 'Z'
...
Alternatively, move the data to below the second part. That way no jump is needed:
...
end:
mov ah, 0x0E ; BIOS.Teletype
mov al, 'Z'
...
varName:
db "Hello World", 0
...
Since this is a bootsector program you might take a look at Disk Read Error while loading sectors into memory where I have listed some things that are important in bootsector programs and that your current program is still missing. e.g. You don't setup any segment registers and you are omiting the DisplayPage parameter for the BIOS.Teletype function.
I am trying to find the smallest value in a given array, and the code I used is this
MOV SI,500
MOV CL,[SI]
MOV CH,00
INC SI
MOV AL,[SI]
DEC CL
INC SI
L1:CMP AL,[SI]
JNC SKIP
MOV AL,[SI]
SKIP:INC SI
LOOP L1
MOV [600],AL
HLT
It compiles fine and runs fine, then I go to "aux" and then to "memory" to type in my input values. I set the address as 0100:0500 and then I give input "01" "02" "03" "04" "05" then against the first row, like this -- https://i.imgur.com/Lrg23B2.png and i click update, and then "RUN" and then go to aux-->memory and check the address 0600, which is where i guess the output would be, and i get just zeroes, like this --- https://i.imgur.com/z2CCtBA.png what is wrong with my code? why am i not getting the minimum value and just zeroes in 0600? I am a total beginner to the 8086 programming, please help.
Don't you need setting the DS segment register to 0100h on top of your program?
You clearly expect to address memory at 0100h:0500h.
Don't you have to use the hexadecimal suffix?
MOV SI,500 uses a decimal 500; you need MOV SI,0500h for hexadecimal!
Note: If you're using a debugger then the hexadecimal notation could well be the default. If you're using a normal assembler then using the correct prefix or suffix is essential.
The loop runs for much too long!
MOV SI,500
MOV CL,[SI] <<<< If THIS reads 01 as is expected...
MOV CH,00
INC SI
MOV AL,[SI]
DEC CL <<<< then THIS will produce 0
INC SI
L1:CMP AL,[SI]
JNC SKIP
MOV AL,[SI]
SKIP:INC SI
LOOP L1 <<<< So THIS runs 65536 times.
MOV [600],AL
HLT
In order to find the minimum you will have to change the jnc skip instruction to jb skip. Currently you're looking for the maximum.
This is a version that you could try. As always: don't just copy but try to understand how it works.
mov ax, 0100h
mov ds, ax
mov si, 0500h
mov cx, 5 ;The number of values in the array
mov al, 255 ;This will become the mininum
L1:
cmp al, [si]
jb SKIP
mov al, [si]
SKIP:
inc si
loop L1 ;This now runs 5 times.
mov [0600h], al
hlt
It would be a good idea to try the code with data that is a bit more random. Perhaps use 3, 2, 5, 1, 4.
I'm learning x86 assembly and I'm trying to write a program that reads a number n (2 digits) from user input and iterate n times.
I've tried many ways but I get an infinite loop or segment fault.
input:
push msgInputQty
call printf
add esp, 4
push quantity
call gets
add esp, 4
mov ecx, 2
mov eax, 0
mov ebx, 0
mov edi, 0
mov dl, 10
transform:
mul dl
mov ebx, 0
mov bl, byte[quantity+edi]
sub bl, 30h
add eax, ebx
inc edi
loop transform
mov ecx, eax
printNTimes:
push msgDig
call printf
add esp, 4
loop printNTimes
I'd like to save in ecx and iterate n times this number
Your ecx register is being blown away by the call to printf.
ecx is a volatile register in some calling conventions and its likely that your loop is being corrupted by what printf is leaving in there.
To begin with, I would follow Raymond's advice in the comment attached to your original question and attach a debugger to witness this behaviour for yourself.
As for a solution, you can try preserving ecx and restoring it after the call to see the difference:
; for example
mov edi,ecx
call printf
mov ecx,edi
There may be more issues here (hard to know for sure since your code is incomplete ... but things like your stack allocations that don't appear to be for any reason are interesting) - but that is a good place to start.
Peter has left a comment under my answer to point out that you could remove the issue and optimize my solution by just not using ecx for your loop at all and instead do it manually, making your code change:
mov edi, eax
printNTimes:
push msgDig
call printf
add esp, 4
dec edi
jnz printNTimes
this is my code that supposed to sorting the array in the way that to find the smallest number but when I'm running that on the 8086 assembly I don't see any result or any thing else but I guess the problem is that my code cannot get out of the loop or something like that is that right?
again I'm saying that the problem on my code is that it doesn't show any result on the window and my program must find the second smallest number in the array.can someone help me to fix the it?
org 100h
; add your code here
DATA SEGMENT
ARR DB 5,3,7,1,9,2,6,8,4
LEN DW $-ARR
SMALL DB ?
SECOND DB ?
DATA ENDS
CODE SEGMENT
ASSUME DS:DATA CS:CODE
START:
MOV AX,DATA
MOV DS,AX
LEA SI,ARR
MOV AL,ARR[SI]
MOV SMALL,AL
MOV CX,LEN
REPEAT1:
MOV AL,ARR[SI]
CMP SMALL,AL
JL NOCHANGE
MOV SMALL,AL
NOCHANGE:
INC SI
LOOP REPEAT1
LEA SI,ARR
MOV AL,ARR[SI]
MOV SECOND,AL
MOV CX,LEN
REPEAT2:
MOV AL,ARR[SI]
CMP SECOND,AL
JL SKIP
CMP SMALL,AL
JGE SKIP
MOV SECOND,AL
SKIP:
INC SI
LOOP REPEAT2
MOV AH,4CH
INT 21H
CODE ENDS
END START
ret
I'm wondering at this point in your class if you are supposed to be able to output numbers as opposed to looking at register values while running a debugger.
As an alternative, insert the commented line into your code to return the value as an error code:
LOOP REPEAT2
MOV AH,4CH
MOV AL,SECOND ;insert this line
INT 21H
CODE ENDS
END START
After assembling and linking the program, run it from a DOS console window (Command prompt). Assume you named it "myprogram.com". Then use these commands:
myprogram
echo %errorlevel%
The errorlevel is the value in AL when using AH=4CH and INT 21H. This only works for single byte values, but that's what you have in this case.
Otherwise you would have to add code to convert the value to decimal and output the result. If these are singe digit values, then the output code is simple:
MOV DL,SECOND
ADD DL,030H
MOV AH,002H
INT 21H
MOV DL,00DH
MOV AH,002H
INT 21H
MOV DL,00AH
MOV AH,002H
INT 21H
or use a string:
SECOND DB ?
STRNG DB 000H,00DH,00AH,'$' ;insert this line
...
MOV AL,SECOND
ADD AL,30
MOV STRNG,AL
MOV DX,OFFSET STRNG
MOV AH,009H
INT 21H
I'm new to assembly language coding and there's this program I'm trying to work out where I initialize an array of letters (in ascii), loop through it, and print it to the console window as a concatenated string. This is what I have so far:
.MODEL flat
.DATA
name1 DB 4Ah, 69h, 6Dh, 6Dh, 79h
.CODE
main PROC
mov ecx, 0
mov esi, offset name1
loop1:
mov dl, [esi]
mov ah, 2
inc esi
inc ecx
cmp ecx, 5
jne loop1
endlp:
mov eax, 4c00h
ret
main ENDP
END
I'm pretty lost. Some of what I have here is from others trying to help me, so sorry if it looks messy.
Everything about your question cries DOS. I would suggest you use the tiny model for these simple demonstration programs.
In the 16-bit environment it's natural to use 16-bit registers.
To execute DOS api services you place the requested parameters in selected registers and store the function number in the AH register. Then you issue an int 21h call.
A more efficient loop will count downward. Often you can avoid the need to compare before looping back because the flags have been set by the dec instruction.
If you place the data of your program below the code that exits to DOS, you avoid mistakenly executing it.
You can write an array of ASCII codes easier as a string. See the 3rd example.
ORG 256 ;This asks for the tiny model
mov cx, 5
mov si, offset array
again:
mov dl, [si]
mov ah, 02h
int 21h ;Display character
inc si
dec cx
jnz again
mov ax, 4C00h
int 21h ;Exit the program
array db 4Ah, 69h, 6Dh, 6Dh, 79h
An alternative program doesn't use the CX counter at all. It suffices to stop when the pointer SI is pointing beyond the last character.
ORG 256 ;This asks for the tiny model
mov si, offset array
again:
mov dl, [si]
mov ah, 02h
int 21h ;Display character
inc si
cmp si, offset array+5
jb again
mov ax, 4C00h
int 21h ;Exit the program
array db 4Ah, 69h, 6Dh, 6Dh, 79h
Another alternative program uses a zero delimiter on the array. To see if the delimiter was reached, you can write cmp dl, 0 je exit but a bit better is to write test dl, dl jz exit.
ORG 256 ;This asks for the tiny model
mov si, offset array
again:
mov dl, [si]
test dl, dl ;Test for zero delimiter
jz exit
mov ah, 02h
int 21h ;Display character
inc si
jmp again
exit:
mov ax, 4C00h
int 21h ;Exit the program
array db 'Jimmy', 0