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).
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.
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.