Setting text and background in Assembly intel - loops

I have a programming assignment to run through and set the background and text of all the possible combinations. I am using a predefined function called SetTextColor which basically sets the values like this:
mov eax, white + (blue * 16)
Essentially this sets the text white and the background blue (to set the background you multiply by 16). Basically the combination is 16 X 16 = 256
TITLE BACKGROUND COLORS (main.asm)
; Description: T
; Author: Chad Peppers
; Revision date: June 21, 2012
INCLUDE Irvine32.inc
.data
COUNT = 16
COUNT2 = 16
LCOUNT DWORD ?
val1 DWORD 0
val2 DWORD 0
.code
main PROC
mov ecx, COUNT
L1:
mov LCOUNT, ecx
mov ecx, COUNT2
L2:
mov eax, val1 + (val2 * 16)
call SetTextColor
inc val2
Loop L2
mov ecx, LCOUNT
Loop L1
call DumpRegs
exit
main ENDP
END main
Basically I am doing a nested loop. My thinking is that I simply do a 1 * (1 * 16) then inc the value in a nested loop until 1 * (16 * 16). I am getting the error below
I am getting the error A2026: constant expected

I imagine the error you are getting is at this line:
mov eax, val1 + (val2 * 16)
You just can't do that. If you intend to multiply val2 by 16 and then add val1 to the result, then you need to implement it step by step (you may come across addressing in the form of a+b*c but a and c need to be registers and b can only be 2, 4 or 8, not 16). Try replacing this line with something like this:
mov eax, val2
imul eax, 16
add aex, val1

Related

Assembly Language x86 - Registers Set and Arithmetic and Loop

I am trying to solve this problem about loops. I am using a push and pop method instead of using a separate register to store data.
.model small
.stack
.code
m proc
mov ax,0b800h
mov es,ax
mov di,7d0h
mov ah,7 ; normal attribute
mov al,'A'
mov cx,5
x: stosw
push ax ;mov dl,al ; dl='A'
push di
mov al,'1'
stosw
pop di
add di,158
pop ax ;mov al,dl
inc al
loop x
mov ah,4ch
int 21h
m endp
end m
I am unable to loop the mov al, '1'.
The output should be like this:
A1
B2
C3
D4
E5
Can anyone show the correct code? Thank you.
Consider the ASCII codes involved:
Letter Digit Difference
A1 65 49 16
B2 66 50 16
C3 67 51 16
D4 68 52 16
E5 69 53 16
See how the difference is always 16 ? That's what next solution exploits:
...
mov ax, 0700h + 'A' ; WhiteOnBlack 'A'
x: stosw ; Stores one letter from {A, B, C, D, E}
sub al, 'A' - '1' ; Convert from letter to digit
stosw ; Stores one digit from {1, 2, 3, 4, 5}
add al, 'A' - '1' + 1 ; Restore AL and at the same time increment
add di, 160 - 4 ; Move down on the screen
cmp al, 'E'
jbe x
...
You don't always need to use CX and the LOOP instruction to work with a loop. Anyway the LOOP instruction is to be avoided for speed reasons!

Sorting only odd/even numbers in assembly, how to copy an array without using already allocated memory?

TL;DR: How to copy elements from one array to another (not all but some)?
I want to perform a sorting algorithm on some array, but so that I only sort odd or even numbers in it, depending on a flag. So my idea was to set a flag on either 0 or 1 and then I'd extract all the numbers that have to be sorted into another array and put -1 (as a marker) on the positions where those numbers were. After that I'd just insert the sorted numbers back into the original array, for example:
arr1: 5 8 2 4 13 9 14 10 9
arr2: 8 2 4 14 10
arr2 (sorted): 2 4 8 10 14
arr1 (without even numbers): 5 -1 -1 -1 13 9 -1 -1 9
arr1 (final): 5 2 4 8 13 9 10 14 9
Now while writing this in a higher language is rather trivial for me, doing it in assembly which I'm learning for a class isn't. The part where I sort the numbers works just fine, but the part that causes me problems is the one where I have to copy the numbers into another array. My main method looks like this:
section .data
arr dd 6,8,1,7,4,2,9,107,10,8,12,16,14,5
len equ ($-arr) / 4 - 1
section .bss
section .text
extern sort
global _start
_start:
mov r8, len
mov esi, arr ; esi points to the start of the array/top of it
call sort
mov rax, 60
mov rdi, 0
syscall
And the subroutine which will do the job (showing only the problematic part):
mov r9d, esi
.export:
mov eax, [r9d]
cdq
div dword [divider]
cmp edx, [flag]
je .add
.continue:
add r9d, 4 ; point to the next number
inc dword [i]
cmp r8d, [i]
jg .export
.add:
mov edi, [r9d]
mov dword [r9d], -1 ; put the number in the old array to -1
sub edi, 4
inc dword [lenNewArray] ; inc the total number of elements in new array
jmp .continue
Anyway what I want to accomplish is that I add an element that matches the condition to some location and then point rdi to that location, when I want to add another element I subtract -4 from rdi so it points to the lower location and put that element there, in the end I'd have rdi pointing to the last element which was extracted, is that possible to be done, and is it a bad way?

Assembly Language (Order Taker)

I'm trying hard to study Assembly language.
I really need help to store different 10 items in an array
I want to build a program that will accept items from 10 choices and it will store it.
Those 10 items have different value.
Example
Item 1 = 10$
Item 2 = 4$
So that when the User tries to choose Item1 and Item2 it will show the
sum of both items.
I'll be gladly be happy if someone can share his/her own code that can store 10 items with the sum of all items. Thanks
Here's my code:
_start:
mov eax,3 ;number bytes to be summed
mov ebx,0 ;EBX will store the sum
mov ecx, x ;ECX will point to the current element to be summed
top: add ebx, [ecx]
add ecx,1 ;move pointer to next element
dec eax ;decrement counter
jnz top ;if counter not 0, then loop again
done:
add ebx, '0'
mov [sum], ebx ;done, store result in "sum"
display:
mov edx,1 ;message length
mov ecx, sum ;message to write
mov ebx, 1 ;file descriptor (stdout)
mov eax, 4 ;system call number (sys_write)
int 0x80 ;call kernel
mov eax, 1 ;system call number (sys_exit)
int 0x80 ;call kernel
section .data
global x
x:
db 2
db 4
db 3
sum:
db 0
My code here does have problem.
x:
db 2
db 4
db 3
sum:
db 0
Since you've defined all of your variables to be of byte type, you must process them as bytes! You're reading and writing dwords in your program.
This could have been OK:
top: add bl, [ecx]
add ecx, 1 ;move pointer to next element
dec eax ;decrement counter
jnz top ;if counter not 0, then loop again
done:
add bl, '0'
mov [sum], bl ;done, store result in "sum"

Assembly language array multiplication bug using bit shift

I have a bug in one of my loops and I can't fix it. It is part of my HW assignment for school.
I have an array, with 20 elements, and I need to multiply every element by 2, using bit shift.
It kind of works, but every time I have a carry, it is adding 2 to the previous element in the array, instead of one. I can't propagate the carry through the array properly.
This is my first semester with assembly, so I appreciate your help. Also, please keep it simple if you can. Thank you.
This is what I want:
0000000009 ==> 0000000018
0000000099 ==> 0000000198
This is what I am getting.
0000000009 ==> 0000000028
0000000099 ==> 00000002108
Here is the code.
ARR1 DB 20 DUP (0)
MULTIPLYING PROC
MOV AX, 0
MOV CX, 19
.WHILE CX != 0
MOV DI, CX
MOV AL, [DIGIT_ARR1+DI]
;MOV BL, 2
;MUL BL
SHL AX, 1
.IF AX > 9 ; IF THE NEW DIGIT IS LARGER THAN 9
SUB AX, 10
MOV AH, 0
MOV [DIGIT_ARR1+DI], AL
DEC DI
ADD [DIGIT_ARR1+DI], 1
.ELSEIF
MOV [DIGIT_ARR1+DI], AL ; IF IT IS LESS THAN 9, THEN JUST INSERT IT BACK INTO THE ARRAY
.ENDIF
DEC CX
.ENDW
RET
MULTIPLYING ENDP
So it turned that Phil was correct. I was rewriting my own data. The trick was to read the value, do the multiplication using bit shift, add the carry (if any) and only then write back to the array. This way I can multiply each element, by two and not corrupt my data.
NOTE FOR BEGINNERS LIKE ME: bit shift will only multiply by two, so if you need to multiply by something else, use mul or imul. Also, bit shift to the right will divide by two.
The loop below will multiply BCD in array by two. Division works the same way, only make sure you process the array the other way and add 10 to each next digit when you have a carry. You will also have to make sure you don't add the carry once you reach the end of the array. Assembly language doesn't check if you are out of bounds of the array.
MULTIPLYING PROC
PUSH CX
PUSH AX
MOV CARRY, 0 ; START WITH EMPTY CARRY FLAG
MOV CX, 19 ; ARRAY SIZE
.WHILE CX > 0
MOV DI, CX ; GET ELEMENT ADDRESS
MOV AL, [ARR1+DI] ; READ THE ELEMENT
SHL AL, 1 ; DOUBLING THE DIGIT
ADD AL, CARRY ; ADD THE CARRY FLAG
MOV CARRY, 0 ; CLEAR THE CARRY FLAG
.IF AL > 9 ; IF THE NEW DIGIT IS LARGER THAN 9
SUB AL, 10
MOV CARRY, 1 ; SET CARRY FLAG
MOV [ARR1+DI], AL ; INSERTING THE DOUBLED DIGIT BACK TO THE ARRAY
.ELSEIF
MOV [DIGIT_ARR1+DI], AL ; IF IT IS LESS THAN 9, INSERT IT BACK INTO THE ARRAY
MOV CARRY, 0
.ENDIF
DEC CX
.ENDW ; END OF MULTIPLICATION PROC
POP AX
POP CX
RET
MULTIPLYING ENDP
I think the problem is that you're writing back to the same array of addresses that you're reading from. When you carry, it is corrupting the calculation.
e.g.
From: 99
Positon 19 = 9
9*2 = 18 (set position 19 to 8, increment position 18 to 10)
Position 18 = 10
10*2 = 20 (set position 18 to 10, increment position 17 to 1)
Position 17 = 1
1*2 = 2 (set position 17 to 2)
Result: 2108
But you still need to do more work because even with empty destination addresses you get
Positon 19 = 9
9*2 = 18 (set position 19 to 8, increment position 18 to 1)
Position 18 = 9
9*2 = 18 (set position 18 to 8, increment position 17 to 1)
Position 17 = 1
1*2 = 2 (set position 17 to 2)
Result: 288
You need to add the 8 to the 1 at position 18 so you get 9. And you dont do a 3rd multiplication because position 17 is empty in the source address array. I hope this makes sense.
You shouldn't get any digit overflow errors when multiplying by 2 like this, but you may need to handle it when multiplying by larger numbers.

nested loop in 8086 assembly language

I am having problem on how exactly should i use loop to get the desire output in this program,
What i want to do is to take input any number from the user and then sort that number in descending order,
I tried my best here to explain every step of the code in the comment.
here is my code,
STSEG SEGMENT
DB 64 DUP(?)
STSEG ENDS
DTSEG SEGMENT
SNAME DB 24 DUP("$")
DTSEG ENDS
CDSEG SEGMENT
MAIN PROC
ASSUME CS:CDSEG, DS:DTSEG, SS:STSEG
MOV AX,DTSEG
MOV DS,AX
MOV ES, AX ;ES:DI
MOV DX, OFFSET STRNG1
MOV AH,09
INT 21H
XOR DX,DX
MOV BYTE PTR SNAME, 40
MOV DX, OFFSET SNAME
MOV AH, 0AH
INT 21H
PUSH DX ;Hold the input number in a stack until we clear the screen and set the cursor
; The clear screen and cursor position code is here which i didn't really mention.
;What we need to do now is to compare first number to each other number and store the greatest
of two on first position.
MOV BX,DX ;Copy un-sorted number to BX,
MOV AX,BX[1] ;the length of the number which is stored on the first position of the string
XOR AH,AH ;Empty AH
MOV CL,AL ;MOVE AL into CL for looping 6 times
SUB CL,1
MOV SI,02H ;the number is stored in string array from the 2nd position
;Suppose the input number is the following,
;[6][3][9][1][8][2][6]
;this is how it should work,
; Loop 6 times , CX = 6
[7][6][3][9][1][8][2][6] ; 7 is length of the number which is already copied in CX above.
; but we need 6 iterations this is why we subtract 1 from CL above.
; 6 > 3 ?
; Yes, then BX[SI] = 6 and BX[SI+1] = 3
; 6 > 9 ?
; NO, then BX[SI] = 9 and BX[SI+2] = 6
; 9 > 1
; Yes, then BX[SI] = 9 and BX[SI+3] = 1
; 9 > 8
; Yes, then BX[SI] = 9 and BX[SI+4] = 8
; 9 > 2
; Yes, then BX[SI] = 9 and BX[SI+5] = 2
; 9 > 6
; Yes, then BX[SI] = 9 and BX[SI+6] = 6
; After first iteration the incomplete sorted number is,
;[9][3][6][1][8][2][6]
;Similarly here i need to loop 5 times now by comparing the 2nd number which is a 3 with all ;the number after it and then loop 4 times then 3 times then two times and then 1 time.
L1:
;Loop 1 must iterate 6 time for the supposed input number,
;but i couldn't be able to write the proper code as i always get out of registers. kindly help me out
L2:
LOOP L2
Loop L1
Kindly help me with the nested loop where i've stucked.
The loop instruction uses the cx register.
So you must either preserve cx for the outer loop with e.g. push cx (before L2:) and pop cx (after loop L2):
mov cx,5
L1:
push cx
mov cx,6
L2:
. . . do stuff inner
loop L2
pop cx
. . . do stuff outer
loop L1
or remember that loop is roughly equal to dec cx jnz, so do e.g.
mov dx,5
L1:
mov cx,6
L2:
... do stuf inner
loop L2
.. do stuff outer
dec dx
jnz L1
Possible off-by-one errors are intended and meant as an exercise for the reader :-)

Resources