Asm Assembler - CX loop never executes - loops

I have a vector and I have to put in the AX register the sum of the numbers that are greater than 50 ( > 50 ).
I do not understand why my loop does not work when I run it. First it compares 100 with 50, jumps at adunare , add 100 to AX but then it exits the loop and terminates the program.
.MODEL SMALL
.STACK 10h
.DATA
vect DB 100,70,3,10,60,200,30
len DB 7
.CODE
begin:
mov ax,#DATA
mov ds,ax
mov ax,0
mov cl,len
mov ch,0
mov si, -1
bucla:
inc si
cmp vect[si],50
ja adunare
jb mic
adunare:
add ax, word ptr vect[si]
mic:
loop bucla
mov ah,4ch
int 21h
END begin

.STACK 10h
With such a small stack the debugger could very well terminate your program as soon as an interrupt occurs, leaving you thinking that the loop doesn't execute.
Specify a larger stack. 256 bytes is a reasonable minimum.
adunare:
add ax, word ptr vect[si]
To add the byte at vect[si] to the word in AX, you have several options:
using an intermediate register like zx485 suggested
clearing the extra register:
xor dx, dx
mov dl, vect[si]
add ax, dx
extending from byte to word in one instruction:
movzx dx, vect[si]
add ax, dx
without an extra register but using a cascaded addition:
add al, vect[si]
adc ah, 0
cmp vect[si],50
ja adunare
jb mic
adunare:
add ax, word ptr vect[si]
mic:
loop bucla
You can write this simpler and if the number 50 were present in the array, it would erroneously be added to the sum. Besides the above and below conditions there's also the equal condition to take care of.
cmp vect[si], 50
jna mic
add al, vect[si]
adc ah, 0
mic:
loop bucla
For perfection you could dismiss the loop instruction (it has a reputation for being slow) and use instead dec cx jnz bucla. This in turn gives you the opportunity to not having to zero CH and rather use dec cl jnz bucla.
Everything together:
xor ax, ax ; This makes AX=0
mov cl, len
mov si, -1
bucla:
inc si
cmp vect[si], 50
jna mic
add al, vect[si]
adc ah, 0
mic:
dec cl
jnz bucla
mov ah, 4ch ; DOS.Terminate (exitcode is in AL)
int 21h
I've tested a good number of variations.
This is a faster version of the loop:
xor ax, ax ; This makes AX=0
xor si, si
mov cl, len
bucla:
cmp vect[si], 50
jna mic
xor dx, dx
mov dl, vect[si]
add ax, dx
mic:
inc si
dec cl
jnz bucla

Related

Subtraction of Two Arrays and Stores Result in 3rd array and display the result on screen in Assembly language 8086

I have already written the code to add TWO arrays and Store the result in 3rd array. But the problem occurs while handling the NEGATIVE SIGN Numbers to display with (-) sign. Follow are the code listed below while subtracting the 6th element of array1 with array 2, result is GARBAGE value Need assistance immediately. After running executing's the code, all signed values are not displaying correctly.
org 100h
Array1 db 1,3,2,2,2,2,2,2,2,2
Array2 db 4,5,6,7,8,9,0,1,2,3
Array3 db 10 dup (?)
lea dx, msg1
mov ah, 9
int 21h
mov cx, 10
mov bx, 0
L1001:
mov al, Array1 [bx]
; Extend (unsigned) AL to AX (to print)
mov ah, 0
call printd
mov ah, 2
mov dl, 09 ;TAB Character
int 21h
inc bx
loop L1001 ;End Loop1
mov ah,2
mov dl,10
int 21h
mov dl,13
int 21h
; print msg2
lea dx, msg2
mov ah, 9
int 21h
; Use loop to print values of Array2
mov cx, 10
mov bx, 0
L1002:
mov al, Array2 [bx]
; Extend (unsigned) AL to AX (to print)
mov ah, 0
call printd
mov ah, 2
mov dl, 09 ;TAB Character
int 21h
inc bx
loop L1002 End Loop2
mov ah,2
mov dl,10
int 21h
mov dl,13
int 21h
; print msg3
lea dx, msg3
mov ah, 9
int 21h
mov cx,10
mov bx, 0
L1003: ; Main Addition
mov al, Array1 [bx]
sub al, Array2 [bx]
mov Array3 [bx], al
; Extend (unsigned) AL to AX (to print)
mov ah, 0
call printd
mov ah, 2
mov dl, 09 ;TAB Character
int 21h
inc bx
loop L1003 ; End of lOOP3
lea dx, pkey
mov ah, 9
int 21h ; output string at ds:dx
; wait for any key....
mov ah, 1
int 21h
mov ax, 4c00h ; exit to operating system.
int 21h
printd proc
; preserve used registers
push ax
push bx
push cx
push dx
; if negative value, print - and call again with -value
cmp ax, 0
jge L1
mov bx, ax
; print -
mov dl, '-'
mov ah, 2
int 21h
; call with -AX
mov ax, bx
neg ax
call printd
jmp L3
L1:
; divide ax by 10
; ( (dx=0:)ax / cx(= 10) )
mov dx, 0
mov cx, 10
div cx
; if quotient is zero, then print remainder
cmp ax, 0
jne L2
add dl, '0'
mov ah, 2
int 21h
jmp L3
L2:
; if the quotient is not zero, we first call
; printd again for the quotient, and then we
; print the remainder.
; call printd for quotient:
call printd
; print the remainder
add dl, '0'
mov ah, 2
int 21h
L3:
; recover used registers
pop dx
pop cx
pop bx
pop ax
ret
printd endp
printud proc ;Print Undecimal Numbers
push ax
push bx
push cx
push dx
mov dx, 0
mov cx, 10
div cx
cmp ax, 0
jne L4
add dl, '0'
mov ah, 2
int 21h
jmp L5
L4:
call printud
add dl, '0'
mov ah, 2
int 21h
L5:
pop dx
pop cx
pop bx
pop ax
ret
printud endp ;
ret
msg1 db "Array 1 = $"
msg2 db "Array 2 = $"
msg3 db "Array 3 = : $"
pkey db "press any key...$"
mov al, Array1 [bx]
sub al, Array2 [bx]
mov Array3 [bx], al
; Extend (unsigned) AL to AX (to print)
mov ah, 0
call printd
You say that your program is having trouble displaying the negative numbers, but your code is never feeding any negative number to the printd routine! Whatever the signed result of the subtraction in AL may be, the mov ah, 0 that follows will produce a positive number in AX and it is AX that printd processes...
You should replace mov ah, 0 by cbw.
But, what is terribly wrong is the placement of the 3 arrays. They can't be at the top of the program like that. The cpu is executing their bytes (data) as if it were instructions (code)!
Move those 3 lines towards the bottom of the source.
It surprised me to see these recursive solutions to display a decimal number. I believe they are correct with one exception though! If you feed printd the negative number -32768 then the program will fall into an infinite loop. This happens because the negation of that particular value is again -32768.
You might want to investigate Displaying numbers with DOS for info about the iterative solution that is surely faster (and could be improved further by outputting the digits all at once).

How to preserve an array or string in x86

I'm programming the game "15 puzzle game" in x86 using tasm asm/dosbox. I want to "save" or "preserve" my array called 'a' that is being declared in my data segment, so that after I swap the bytes around using upArrow, downArrow, etc... and then I press 'n' for new game, I can set my array 'a' back to it's original state as it was declared in my data segment. Here is my code:
.MODEL TINY
.386
.DATA
PROMPT DB "Enter q to quit, arrow keys to move, n to restart (new game) HAPPY HOLIDAYS!! :)$"
;this is board preset A
a DB 201,205,205,205,205,203,205,205,205,205,203,205,205,205,205,203,205,205,205,205,203,205,205,205,205,203,205,205,205,205,187,
DB 186,255,48,50,255,186,255,48,49,255,186,255,48,51,255,186,255,48,52,255,186,255,48,53,255,186,255,48,54,255,186,
DB 204,205,205,205,205,206,205,205,205,205,206,205,205,205,205,206,205,205,205,205,206,205,205,205,205,206,205,205,205,205,185,
DB 186,255,48,55,255,186,255,48,56,255,186,255,48,57,255,186,255,49,48,255,186,255,49,49,255,186,255,49,50,255,186,
DB 204,205,205,205,205,206,205,205,205,205,206,205,205,205,205,206,205,205,205,205,206,205,205,205,205,206,205,205,205,205,185,
DB 186,255,49,51,255,186,255,49,52,255,186,255,49,53,255,186,255,49,54,255,186,255,49,55,255,186,255,255,255,255,186,
DB 204,205,205,205,205,206,205,205,205,205,206,205,205,205,205,206,205,205,205,205,206,205,205,205,205,206,205,205,205,205,185,
DB 186,255,49,56,255,186,255,49,57,255,186,255,50,48,255,186,255,50,49,255,186,255,50,50,255,186,255,50,51,255,186,
DB 200,205,205,205,205,202,205,205,205,205,202,205,205,205,205,202,205,205,205,205,202,205,205,205,205,202,205,205,205,205,188,"$"
col DB 0
row DB 0
board DB 0
.CODE
org 100h
MAIN PROC
;initialize display step 0
MOV AH, 00h
MOV AL, 03h
INT 10h
MOV AX, 0B800h
MOV ES, AX
XOR di,di
;initialize configuration and dislay prompt step 1
newGame:
call initConfig
;display board step 2
;wait for key step 3
game:
;print board
call printBoard1
;get cursor x y
call SetCursor
MOV AH, 0
INT 16H
MOV BL, AL
;up arrow
CMP AH, 48h
jz upArrow
;down arrow
CMP AH, 50h
jz downArrow
;right arrow
CMP AH, 4dh
jz rightArrow
;left arrow
CMP AH, 4bh
jz leftArrow
;lowercase q
CMP AL, 71h
jz EXIT
;uppercase q
CMP AL, 51h
jz EXIT
;lowercase n
CMP AL, 6eh
jz newGame
;uppercase n
CMP AL, 4eh
jz newGame
jmp game
MAIN ENDP
EXIT:
MOV AH, 4CH ; return control to DOS
INT 21H
SetCursor:
mov dl, col
mov dh, row
mov bh, 0
mov ah, 02h
int 10h
ret
getStrlen:
lodsb
cmp al, 24h
je strlen_end
inc bx
jmp getStrlen
strlen_end:
ret
loadAndDisplayStr:
lodsb
stosw
dec cx
jne loadAndDisplayStr
ret
printBoard1:
MOV board, 1
xor dx,dx
xor ax,ax
mov cx, 9
myloop1:
push cx
lea si, a
add si, dx
mov cx, 31
mov di, ax
push ax
mov ah, 4
call loadAndDisplayStr
pop ax
add ax, 160
add dx, 32
pop cx
dec cx
jnz myloop1
ret
upArrow:
xor si, si
xor di, di
lea bx, a
mov ax, 32
sub row, 2
mul row
add al, col
mov di, ax
mov ax, 32
add row, 2
mul row
add al, col
mov si, ax
mov dx, [bx+si]
xchg dx, [bx+di]
xchg [bx+si], dx
sub row, 2
jmp game
downArrow:
xor si, si
xor di, di
lea bx, a
mov ax, 32
add row, 2
mul row
add al, col
mov di, ax
mov ax, 32
sub row, 2
mul row
add al, col
mov si, ax
mov dx, [bx+si]
xchg dx, [bx+di]
xchg [bx+si], dx
add row, 2
jmp game
leftArrow:
xor si, si
xor di, di
lea bx, a
mov ax, 32
sub col, 5
mul row
add al, col
mov di, ax
mov ax, 32
add col, 5
mul row
add al, col
mov si, ax
mov dx, [bx+si]
xchg dx, [bx+di]
xchg [bx+si], dx
sub col, 5
jmp game
rightArrow:
xor si, si
xor di, di
lea bx, a
mov ax, 32
add col, 5
mul row
add al, col
mov di, ax
mov ax, 32
sub col, 5
mul row
add al, col
mov si, ax
mov dx, [bx+si]
xchg dx, [bx+di]
xchg [bx+si], dx
add col, 5
jmp game
initConfig:
;put the cursor at 00
mov col, 27
mov row, 5
;gets strlen of prompt and stores it in BX
lea si, PROMPT
xor bx, bx
call getStrlen
;display prompt
lea si, PROMPT
mov cx, bx
mov ah, 2
mov di, 5a0h
call loadAndDisplayStr
ret
END MAIN
The way I see it is there are 2 ways of doing this. One way would be to create an empty array, and every time the user makes a move (up/down/left/right) I can push this to a stack, and then when the user hits 'n' for new game, I just pop through that stack and reverse all the moves.
Another alternative would be to create 2 identical boards (arrays/string) 'a' and 'b', and then the user would manipulate board 'a' till they decide to hit 'n' for a new game, and then I would some how set 'a' = 'b'
There's no magic way, you just have to copy the array like you would in C.
I'd suggest having one master copy of the data that you keep clean / untouched, never ever writing into it.
Allocate uninitialized space for the working game state somewhere, e.g. on the stack or in the BSS1.
At the start of every game (including the first one), copy the preset whole array to the scratch space for the current game. (e.g. with rep movsb or rep movsw after setting CX, SI, and DI. ES and DS segment regs are already equal segment because of .model tiny. i.e. implement a memcpy however you like.)
So you don't need to write the initializer data twice or anything like that, and only one copy of it needs to be in the file.
And no you don't need any exchanging, just a block copy. Get the assembler to calculate the size of the whole thing by putting a label at the end, or put datasize = $ - a right after the end of a to get the size in bytes.
Footnote 1: See #MichaelPetch's comment for details on how to declare a label in the .data? segment so you can use normal label/symbol syntax. Like gamestate datasize dup(?), where datasize is an = or equ constant you got the assembler to calculate earlier from the size of the preset.
I think .data? is just space past the end of where DOS loads your .com file, and you can use space from there out to near the end of a 64k segment where the program-loader put your stack. (Unlike the .bss under a modern OS is not zeroed to start with. That's fine for this, you want to write the space you use before you read/modify it anyway.)
#DavidWohlferd also suggests you could re-read part of the executable from disk, with DOS file open/read system calls. That could be the start of a save-game mechanism. In its simplest form, if the first n bytes of your program are all read-only (code and constant data) apart from this game-state array, you could read the first n bytes of the raw .com file into memory at ds:100h (or cs or es, it's all the same in a tiny memory model). Overwriting instructions with themselves (like a jmp rel16 over the data) is fine.

Negative Numbers MASM Input and Output

I am in the process of writing a byte sized poly derivative app in MASM x8086 and it has to be able to receive negative coefficients.
I understand that binary can be represented in signed and unsigned form. But I am looking for a way to receive a signed integer so that I can avoid another array. Or is there a way to define my variable as a signed integer?
Below is my integer input procedure.
TEN db 10 ;;; constant
num db ? ;;; coefficient
;;; bh is the degree
get_int PROC
lea si, string ; replaces the ? in the string with the degree
add si, 13h
mov dl, bh
add dl, 30h
mov [si], dl
mov ah, 09h
lea dx, string ; prompt
int 21h
mov ah, 0Ah
lea dx, buffString ; user input
int 21h
lea si, buffString ; point to count byte
inc si
mov ch, 00h ; cx = count
mov cl, [si]
add si, cx ; si points to end of string
mov dl, 00h ; hold result(dl)
mov bl, 01h ; hold 10^x (bl)
loop1:
mov al, [si] ; prep for char ---> number conversion
cmp al, '-'
je negativeSign
sub al, 30h ; convert
mul bl ; ax = al*bl
add dl, al ; sum of results
mov al, bl ; preload for instruction
mul TEN ; TEN is variable predefined as 10
mov bl, al
jmp overNegative
negativeSign:
mov dh, 00h
mov [si], dh
overNegative:
dec si
loop loop1 ; loop instruction uses cx as index counter once zero breaks
mov num, dl
ret
get_int ENDP
; output is num
When, while interpreting the input, you stumble upon the "-" character it is a save assumption that you reached the start of the number. Therefore you should bail out of the loop. I don't see any point in replacing the "-" character by a zero!
What you do need to do is negate the number to obtain the correct signed result:
loop1:
mov al, [si] ; prep for char ---> number conversion
cmp al, '-'
je negativeSign
sub al, 30h ; convert
mul bl ; ax = al*bl
add dl, al ; sum of results
mov al, bl ; preload for instruction
mul TEN ; TEN is variable predefined as 10
mov bl, al
dec si
loop loop1 ; loop instruction uses cx as index counter once zero breaks
mov num, dl ;Positive number [0,127]
ret
negativeSign:
mov dh, 00h <<<<<<< Need this as a flag?
neg dl
mov num, dl ;Negative number [-128,-1]
ret

8086 Assembly - Better data storage/manipulation?

I am working on a project for class, and it works as required by the rubric, though I am wondering if there is a slightly better way to implement a few things. I was docked a few points for an unnecessary 'mov' in another project. Here is problem 1.
"If—else (34 points): Write a program that asks the user to enter a single digit. If that digit is less 5, you will state so and you will add 5 to it and store it in a variable; if the digit is greater than 5, you will state so and then subtract 5 from it and store it in a variable; if the digit is 5, you will add 3 to it and state so and store it in a variable."
org 100h
mov dx, offset start ;move start of string address 'start' into dx
mov ah, 09h
int 21h ;print the string stored at DS:DX
mov ah, 01h ;function for getting keyboard input
int 21h
sub al, 30h ;subtract 30h to store our number as hexadecimal
mov bl, al ;copying data to BL as the following commands manipulate the data
;at AL.
cmp bl, 5 ;BL = AL
jz ifZero ;jump to ifZero if BL = 5
jl ifLess ;jump to isLess if BL < 5
jg ifGreater ;jump to ifGreater if BL > 5
ifZero: ;direct console output function
mov ah, 06h
mov dl, 0Ah
int 21h
mov dl, 0Dh
int 21h ;print newline and character return
add bl, 03h ;add 3 to BL, BL = 8
mov temp, bl
mov dx, offset eq ;move start of string address 'eq' into dx
mov ah, 09h
int 21h ;print string
jmp exit ;unconditional jump to end program
ifLess: ;direct console output function
mov ah, 06h
mov dl, 0aH
int 21h
mov dl, 0Dh
int 21h ;print newline and character return
add bl, 05h ;add 5 to BL
mov temp, bl
mov dx, offset less ;move start of string address 'less' into dx
mov ah, 09h
int 21h ;print string
jmp exit ;unconditional jump to end program
ifGreater:
mov ah, 06h
mov dl, 0ah
int 21h
mov dl, 0dh
int 21h ;print newline and character return
sub bl, 05h ;subtract 5 from BL
mov temp, bl
mov dx, offset great ;move starting address of string 'great' into dx
mov ah, 09h
int 21h ;print string
jmp exit ;unconditional jump to end program
exit:
ret
temp db ?
start db "Please enter a number: $"
less db "Less than 5... adding 5 $"
great db "Greater than 5... subtracting 5 $"
eq db "Equal to 5... adding 3 $"
in this case, would 'mov bl, al' be not needed? Running through the disassembler shows that the data in AL changes after most of these commands. Is this supposed to happen? Is there a better way to do so?
Problem 3:
Counter-controlled loop. The program will ask the user to enter a character and then it will display
that character with a label five times
For example:
Enter a character: A
You entered: A
org 100h
mov cx, 05h ;counter controlled loop, start as 5
LabelLoop:
mov dx, offset prompt ;move string offset to dx
mov ah, 09h ;function for printing string from dx
int 21h
mov ah, 01h ;function to read character from keyboard
int 21h
mov bl, al ;preserving character read by copying to BL
;as register data for AL will be changing
;due to various functions
mov ah, 06h ;function for direct console output
mov dl, 0ah
int 21h
mov dl, 0dh ;these just make the text appear on a new
;line
int 21h
mov dx, offset output ;move the memory offset of output to dx
mov ah, 09h ;printing another string
int 21h
mov ah, 02h ;function to write a character to console
;gets the value from DL
mov dl, bl ;so we copy BL to DL and print it
int 21h
jmp newLine ;we unconditionally jump to the newLine
;label and print a new line for the program
;to run again
newLine:
mov ah, 06h
mov dl, 0ah
int 21h
mov dl, 0dh
int 21h
loop LabelLoop ;we jump to LabelLoop and CX = CX - 1
mov dx, offset goodbye
mov ah, 09h
int 21h
ret
prompt db 'Enter a character: $'
output db 'You entered: $'
goodbye db 'Good bye!$'
So, my question for these problems, is there a better way to do this? keyboard input is stored in AL, but the register value changes for each time i do a mov function into AH, whether string printing or character printing. in order to avoid a variable (since it wasn't a part of the requirements) or allocating it to memory (which we haven't learned), I moved the data to a different register. Is this an unnecessary 'mov' for either program?
edit: i realize that AL = DL after
mov ah, 06h
mov dl, 0ah
int 21h ;AL = DL after execution
cmp bl, 5 ;BL = AL
jz ifZero ;jump to ifZero if BL = 5
jl ifLess ;jump to isLess if BL < 5
jg ifGreater ;jump to ifGreater if BL > 5
ifZero:
The first improvement you should do is making use of the possibility to fall-through in the code. Don't use jz ifZero but rather fall through as equality is the only state that remains after jl and jg. Also ifEqual would be a more correct name for this state.
cmp bl, 5 ;BL = AL
jl ifLess ;jump to isLess if BL < 5
jg ifGreater ;jump to ifGreater if BL > 5
ifEqual:
A second optimization will be to get rid of all of those direct console outputs for CR and LF. You should incorporate these in the messages that you will print. Doing so will also remove the need to copy AL to BL using mov bl, al (you specifically asked this):
less db 13,10,"Less than 5... adding 5 $"
great db 13,10,"Greater than 5... subtracting 5 $"
eq db 13,10,"Equal to 5... adding 3 $"
Here's another opportunity to fall through:
jmp exit ;unconditional jump to end program
exit:
Your second program can benefit from these advices too.

Assembler read full numbers from txt file

I am stuck at point where I need to read 3 numbers from created buffer of text file. I've tryed reading every byte, but no luck if the number is bigger than 9.
Steps that I do:
Open text file
Read file's content into created buffer
Put every buffers byte into different register (ax, bx, cx, dx).
The problem is, it reads 1 byte (mov ax, buffer[0]) at a time: if my text file is (10 10 1), it reads 1 then 0 then space symbol(ascii 20) and so on. Should I do cycle that converts and adds every byte to one register while it doesn't detect space symbol? Or is there a possibility to read whole number at one time? Here's the code:
.model small
bufferLen equ 16
.stack 100h
.data
duom db "duom.txt", 0
fident dw 0
buffer db bufferLen dup (?)
.code
start:
mov dx, #data
mov ds, dx
mov bx, 81h
tikrinam: ; not important
mov ax, es:[bx]
inc bx
cmp al, 13
je openf
cmp al, 20h
je tikrinam
cmp ax, "?/"
jne openf
mov ax, es:[bx]
cmp ah, 13
je abouthlp
jmp openf
abouthlp:
mov dx, offset about
mov ah, 09h
int 21h
jmp ending
openf:
mov ah, 3Dh
mov al, 0
mov dx, offset duom
int 21h
mov [fident], ax
readf:
mov ah, 3Fh
mov bx, [fident]
mov cx, bufferLen
mov dx, offset buffer
int 21h
mov al, buffer[0]
mov bl, buffer[1]
mov cl, buffer[2]
I've found the solution if anyone is having same problem:
changeNumbers:
push ax
mov ax, 0
cmp cl, 0
je change
temp1:
mov ch, 0
mov cl, buffer[si]
inc si
cmp cl, 32
je changeNumbers
cmp cl, 0
je changeNumbers
sub cl, 48
mul abc
add ax, cx
jmp temp1
Basically what I did was read every byte and if the number is >9 then add cx to ax and multiply it by 10. Then just push it to stack for further usage. Brain is an amazing thing, I'd say.

Resources